Added UIDataBind: simple two way data binding between data and widgets.

UIDocFindReplace: first working version completed.
TextDocument: Fixed findTextLast when using case-insensitive search.
StyleSheet: Added StyleSheet::markerExists.
ecode: DocSearchController minor refactor.
This commit is contained in:
Martín Lucas Golini
2022-09-04 04:06:38 -03:00
parent cb2274397e
commit 0a70817ed1
22 changed files with 490 additions and 165 deletions

View File

@@ -19,7 +19,7 @@
* Implement a rich text view.
* Provide some facilities for basic data-binding.
* Provide some facilities for basic data-binding (WIP).
### CSS
@@ -29,8 +29,6 @@
### UICodeEditor
* Implement and embed a default find-replace widget inside the editor.
* Add better support for double-width characters.
* Add new CSS properties related to the widget.

View File

@@ -82,4 +82,6 @@
#include <eepp/ui/models/sortingproxymodel.hpp>
#include <eepp/ui/models/widgettreemodel.hpp>
#include <eepp/ui/uidatabind.hpp>
#endif

View File

@@ -91,6 +91,7 @@ enum class PropertyId : Uint32 {
TabSeparation = String::hash( "tab-separation" ),
TabHeight = String::hash( "tab-height" ),
Selected = String::hash( "selected" ),
Checked = String::hash( "checked" ),
PopUpToRoot = String::hash( "popup-to-root" ),
MaxVisibleItems = String::hash( "max-visible-items" ),
SelectedIndex = String::hash( "selected-index" ),

View File

@@ -53,6 +53,8 @@ class EE_API StyleSheet {
void removeAllWithMarker( const Uint32& marker );
bool markerExists( const Uint32& marker ) const;
protected:
Uint32 mMarker{ 0 };
std::vector<std::shared_ptr<StyleSheetStyle>> mNodes;

View File

@@ -4,22 +4,27 @@
#include <eepp/ui/base.hpp>
#include <eepp/ui/doc/textdocument.hpp>
#include <eepp/ui/uicodeeditor.hpp>
#include <eepp/ui/uidatabind.hpp>
#include <eepp/ui/uilinearlayout.hpp>
#include <eepp/ui/uiselectbutton.hpp>
#include <eepp/ui/uitextinput.hpp>
#include <eepp/ui/widgetcommandexecuter.hpp>
#include <memory>
namespace EE { namespace UI { namespace Tools {
class EE_API UIDocFindReplace : public UILinearLayout, public WidgetCommandExecuter {
public:
static std::unordered_map<std::string, std::string> getDefaultKeybindings() {
return { { "mod+g", "repeat-find" }, { "escape", "close-find-replace" },
{ "mod+r", "replace-selection" }, { "mod+shift+n", "find-and-replace" },
{ "mod+shift+r", "replace-all" }, { "mod+s", "change-case" },
{ "mod+w", "change-whole-word" }, { "mod+l", "toggle-lua-pattern" },
{ "mod+e", "change-escape-sequence" } };
return { { "mod+g", "repeat-find" },
{ "escape", "close-find-replace" },
{ "mod+r", "replace-selection" },
{ "mod+shift+n", "find-and-replace" },
{ "mod+shift+r", "replace-all" },
{ "mod+s", "change-case" },
{ "mod+w", "change-whole-word" },
{ "mod+l", "toggle-lua-pattern" },
{ "mod+e", "change-escape-sequence" },
{ "mod+shift+g", "find-prev" } };
}
static UIDocFindReplace*
@@ -30,7 +35,7 @@ class EE_API UIDocFindReplace : public UILinearLayout, public WidgetCommandExecu
void setDoc( const std::shared_ptr<Doc::TextDocument>& doc );
virtual void show();
virtual void show( bool expanded = false );
virtual void hide();
@@ -58,6 +63,8 @@ class EE_API UIDocFindReplace : public UILinearLayout, public WidgetCommandExecu
UIWidget* mToggle{ nullptr };
UIWidget* mReplaceBox{ nullptr };
std::shared_ptr<Doc::TextDocument> mDoc;
std::vector<std::unique_ptr<UIDataBind<bool>>> mDataBinds;
std::unique_ptr<UIDataBind<TextDocument::FindReplaceType>> mPatternBind;
UIDocFindReplace(
UIWidget* parent, const std::shared_ptr<Doc::TextDocument>& doc,

View File

@@ -0,0 +1,143 @@
#ifndef EE_UI_UIDATABIND_HPP
#define EE_UI_UIDATABIND_HPP
#include <eepp/ui/uiwidget.hpp>
#include <set>
namespace EE { namespace UI {
template <typename T> class UIDataBind {
public:
struct Converter {
Converter(
std::function<bool( const UIDataBind<T>*, T&, const std::string& )> toVal =
[]( const UIDataBind<T>*, T& val, const std::string& str ) {
auto base = std::is_same<T, bool>::value ? std::boolalpha : std::dec;
return String::fromString( val, str, base );
},
std::function<bool( const UIDataBind<T>*, std::string&, const T& )> fromVal =
[]( const UIDataBind<T>*, std::string& str, const T& val ) {
str = String::toString( val );
return true;
} ) :
toVal( toVal ), fromVal( fromVal ) {}
std::function<bool( const UIDataBind<T>*, T&, const std::string& )> toVal;
std::function<bool( const UIDataBind<T>*, std::string&, const T& )> fromVal;
};
UIDataBind( T* t, std::set<UIWidget*> widgets, const Converter& converter = {},
const std::string& valueKey = "value" ) :
data( t ),
widgets( widgets ),
property( StyleSheetSpecification::instance()->getProperty( valueKey ) ),
converter( converter ) {
for ( auto widget : widgets )
bindListeners( widget );
set( *data );
}
UIDataBind( T* t, UIWidget* widget, const Converter& converter = {},
const std::string& valueKey = "value" ) :
data( t ),
widgets( { widget } ),
property( StyleSheetSpecification::instance()->getProperty( valueKey ) ),
converter( converter ) {
for ( auto widget : widgets )
bindListeners( widget );
set( *data );
}
void set( const T& t ) {
inSetValue = true;
*data = t;
setValueChange();
inSetValue = false;
}
const T& get() const { return *data; }
void bind( UIWidget* widget ) {
bindListeners( widget );
widgets.insert( widget );
inSetValue = true;
widget->applyProperty( StyleSheetProperty( property, String::toString( data ) ) );
inSetValue = false;
}
void unbind( UIWidget* widget ) {
if ( widgets.find( widget ) == widgets.end() )
return;
widget->removeEventListener( valueCbs[widget] );
widget->removeEventListener( closeCbs[widget] );
valueCbs.erase( widget );
closeCbs.erase( widget );
widgets.erase( widget );
}
~UIDataBind() {
for ( auto widget : widgets ) {
widget->removeEventListener( valueCbs[widget] );
widget->removeEventListener( closeCbs[widget] );
}
}
const PropertyDefinition* getPropertyDefinition() const { return property; }
protected:
T* data;
std::set<UIWidget*> widgets;
std::map<UIWidget*, Uint32> valueCbs;
std::map<UIWidget*, Uint32> closeCbs;
bool inSetValue{ false };
const PropertyDefinition* property{ nullptr };
Converter converter;
void bindListeners( UIWidget* widget ) {
valueCbs[widget] =
widget->addEventListener( Event::OnValueChange, [this]( const Event* event ) {
processValueChange( event->getNode()->asType<UIWidget>() );
} );
closeCbs[widget] = widget->addEventListener( Event::OnClose, [this]( const Event* event ) {
closeCbs.erase( event->getNode()->asType<UIWidget>() );
this->widgets.erase( event->getNode()->asType<UIWidget>() );
} );
}
std::string dataToString() const {
std::string str;
if ( !converter.fromVal( this, str, *data ) ) {
Log::error( "UIDataBind::dataToString converter::fromVal: unable to convert value "
"to string." );
}
return str;
}
void processValueChange( UIWidget* emitter ) {
if ( inSetValue )
return;
bool success = false;
T val;
success = converter.toVal( this, val, emitter->getPropertyString( property ) );
if ( success ) {
*data = val;
StyleSheetProperty prop( property, dataToString() );
inSetValue = true;
for ( auto widget : widgets ) {
if ( widget != emitter )
widget->applyProperty( prop );
}
inSetValue = false;
}
}
void setValueChange() {
StyleSheetProperty prop( property, dataToString() );
for ( auto widget : widgets )
widget->applyProperty( prop );
}
};
}} // namespace EE::UI
#endif // EE_UI_UIDATABIND_HPP

View File

@@ -25,6 +25,11 @@ class EE_API UIMenuCheckBox : public UIMenuItem {
void switchActive();
virtual bool applyProperty( const StyleSheetProperty& attribute );
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex ) const;
protected:
bool mActive;
UISkin* mSkinActive;

View File

@@ -25,6 +25,11 @@ class EE_API UIMenuRadioButton : public UIMenuItem {
void switchActive();
virtual bool applyProperty( const StyleSheetProperty& attribute );
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex = 0 ) const;
protected:
bool mActive;
UISkin* mSkinActive;

View File

@@ -215,6 +215,8 @@ class EE_API UIWidget : public UINode {
bool isTabStop() const;
void setTabStop();
UIWidget* getNextTabWidget() const;
bool hasPseudoClass( const std::string& pseudoCls ) const;
@@ -254,6 +256,8 @@ class EE_API UIWidget : public UINode {
virtual void onChildCountChange( Node* child, const bool& removed );
virtual Uint32 onKeyDown( const KeyEvent& event );
virtual Uint32 onMouseMove( const Vector2i& Pos, const Uint32& Flags );
virtual Uint32 onMouseOver( const Vector2i& Pos, const Uint32& Flags );

View File

@@ -361,6 +361,7 @@
../../include/eepp/ui/uicodeeditor.hpp
../../include/eepp/ui/uicombobox.hpp
../../include/eepp/ui/uiconsole.hpp
../../include/eepp/ui/uidatabind.hpp
../../include/eepp/ui/uidropdownlist.hpp
../../include/eepp/ui/uieventdispatcher.hpp
../../include/eepp/ui/uifiledialog.hpp

View File

@@ -98,6 +98,14 @@ void StyleSheet::removeAllWithMarker( const Uint32& marker ) {
invalidateCache();
}
bool StyleSheet::markerExists( const Uint32& marker ) const {
for ( auto node : mNodes ) {
if ( node->getMarker() == marker )
return true;
}
return false;
}
bool StyleSheet::addStyleToNodeIndex( StyleSheetStyle* style ) {
const std::string& id = style->getSelector().getSelectorId();
const std::string& tag = style->getSelector().getSelectorTagName();

View File

@@ -1579,11 +1579,13 @@ TextRange TextDocument::findTextLast( String text, TextPosition from, const bool
if ( i == from.line() ) {
col = caseSensitive
? findLastType( line( i ).getText().substr( 0, from.column() ), text, type )
: findLastType( String::toLower( line( i ).getText() ), text, type );
: findLastType(
String::toLower( line( i ).getText().substr( 0, from.column() ) ), text,
type );
} else if ( i == to.line() ) {
col = caseSensitive
? findLastType( line( i ).getText().substr( to.column() ), text, type )
: findLastType( String::toLower( line( i ).getText() ).substr( to.column() ),
: findLastType( String::toLower( line( i ).getText().substr( to.column() ) ),
text, type );
if ( String::StringType::npos != col.first ) {
col.first += to.column();

View File

@@ -1,14 +1,15 @@
#include "eepp/window/clipboard.hpp"
#include <eepp/scene/actions/actions.hpp>
#include <eepp/ui/css/stylesheetparser.hpp>
#include <eepp/ui/tools/uidocfindreplace.hpp>
#include <eepp/ui/uiscenenode.hpp>
#include <eepp/window/clipboard.hpp>
#include <eepp/window/window.hpp>
namespace EE { namespace UI { namespace Tools {
const char DOC_FIND_REPLACE_XML[] = R"xml(
<style>
<![CDATA[
const char* DOC_FIND_REPLACE_CSS_MARKER = "ce_find_replace_box_marker";
const char DOC_FIND_REPLACE_CSS[] = R"css(
.ce_find_replace_box {
background-color: var(--list-back);
}
@@ -95,8 +96,13 @@ const char DOC_FIND_REPLACE_XML[] = R"xml(
.ce_find_replace_box pushbutton.replace-all-button {
icon: url("data:image/svg,<svg width='16' height='16' viewBox='0 0 16 16' fill='#ffffff'><path fill-rule='evenodd' clip-rule='evenodd' d='M11.6 2.677c.147-.31.356-.465.626-.465.248 0 .44.118.573.353.134.236.201.557.201.966 0 .443-.078.798-.235 1.067-.156.268-.365.402-.627.402-.237 0-.416-.125-.537-.374h-.008v.31H11V1h.593v1.677h.008zm-.016 1.1a.78.78 0 0 0 .107.426c.071.113.163.169.274.169.136 0 .24-.072.314-.216.075-.145.113-.35.113-.615 0-.22-.035-.39-.104-.514-.067-.124-.164-.187-.29-.187-.12 0-.219.062-.297.185a.886.886 0 0 0-.117.48v.272zM4.12 7.695L2 5.568l.662-.662 1.006 1v-1.51A1.39 1.39 0 0 1 5.055 3H7.4v.905H5.055a.49.49 0 0 0-.468.493l.007 1.5.949-.944.656.656-2.08 2.085zM9.356 4.93H10V3.22C10 2.408 9.685 2 9.056 2c-.135 0-.285.024-.45.073a1.444 1.444 0 0 0-.388.167v.665c.237-.203.487-.304.75-.304.261 0 .392.156.392.469l-.6.103c-.506.086-.76.406-.76.961 0 .263.061.473.183.631A.61.61 0 0 0 8.69 5c.29 0 .509-.16.657-.48h.009v.41zm.004-1.355v.193a.75.75 0 0 1-.12.436.368.368 0 0 1-.313.17.276.276 0 0 1-.22-.095.38.38 0 0 1-.08-.248c0-.222.11-.351.332-.389l.4-.067zM7 12.93h-.644v-.41h-.009c-.148.32-.367.48-.657.48a.61.61 0 0 1-.507-.235c-.122-.158-.183-.368-.183-.63 0-.556.254-.876.76-.962l.6-.103c0-.313-.13-.47-.392-.47-.263 0-.513.102-.75.305v-.665c.095-.063.224-.119.388-.167.165-.049.315-.073.45-.073.63 0 .944.407.944 1.22v1.71zm-.64-1.162v-.193l-.4.068c-.222.037-.333.166-.333.388 0 .1.027.183.08.248a.276.276 0 0 0 .22.095.368.368 0 0 0 .312-.17c.08-.116.12-.26.12-.436zM9.262 13c.321 0 .568-.058.738-.173v-.71a.9.9 0 0 1-.552.207.619.619 0 0 1-.5-.215c-.12-.145-.181-.345-.181-.598 0-.26.063-.464.189-.612a.644.644 0 0 1 .516-.223c.194 0 .37.069.528.207v-.749c-.129-.09-.338-.134-.626-.134-.417 0-.751.14-1.001.422-.249.28-.373.662-.373 1.148 0 .42.116.764.349 1.03.232.267.537.4.913.4zM2 9l1-1h9l1 1v5l-1 1H3l-1-1V9zm1 0v5h9V9H3zm3-2l1-1h7l1 1v5l-1 1V7H6z'/></svg>");
}
]]>
</style>
.ce_find_replace_box .input-find.error,
.ce_find_replace_box .input-replace.error {
border-color: #ff4040;
}
)css";
const char DOC_FIND_REPLACE_XML[] = R"xml(
<hbox class="ce_find_replace_box" layout_width="wrap_content" layout_height="wrap_content" layout_gravity="right|top" layout-margin-right="32dp">
<!-- <Widget class="expander" layout_width="2dp" layout_height="match_parent" /> -->
<button class="find_replace_toggle" layout_width="16dp" layout_height="wrap_content" padding="2dp" layout_gravity="center" />
@@ -159,8 +165,17 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
getKeyBindings().addKeybindsStringUnordered( keybindings );
if ( !parent->getUISceneNode()->getStyleSheet().markerExists(
String::hash( DOC_FIND_REPLACE_CSS_MARKER ) ) ) {
CSS::StyleSheetParser parser;
parser.loadFromMemory( (const Uint8*)DOC_FIND_REPLACE_CSS,
eeARRAY_SIZE( DOC_FIND_REPLACE_CSS ) );
parent->getUISceneNode()->getStyleSheet().combineStyleSheet( parser.getStyleSheet() );
}
parent->getUISceneNode()->loadLayoutFromMemory( DOC_FIND_REPLACE_XML,
eeARRAY_SIZE( DOC_FIND_REPLACE_XML ), this );
setParent( parent );
mReplaceBox = querySelector( ".replace_box" );
@@ -229,6 +244,19 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
addCommand( "toggle-lua-pattern",
[&] { mLuaPattern->setSelected( !mLuaPattern->isSelected() ); } );
mCaseSensitive->setTooltipText( mCaseSensitive->getTooltipText() + " (" +
getKeyBindings().getCommandKeybindString( "change-case" ) +
")" );
mWholeWord->setTooltipText( mWholeWord->getTooltipText() + " (" +
getKeyBindings().getCommandKeybindString( "change-whole-word" ) +
")" );
mEscapeSequences->setTooltipText(
mEscapeSequences->getTooltipText() + " (" +
getKeyBindings().getCommandKeybindString( "change-escape-sequence" ) + ")" );
mLuaPattern->setTooltipText( mLuaPattern->getTooltipText() + " (" +
getKeyBindings().getCommandKeybindString( "toggle-lua-pattern" ) +
")" );
mReplaceInput = querySelector<UITextInput>( ".input-replace" );
auto addClickListener = [&]( UIWidget* widget, std::string cmd ) {
@@ -254,9 +282,43 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
addClickListener( querySelector( ".ce_find_replace_box .replace-all-button" ), "replace-all" );
addClickListener( querySelector( ".ce_find_replace_box .exit-button" ), "close-find-replace" );
mFindInput->setTabStop();
mReplaceInput->setTabStop();
mFindInput->addEventListener( Event::OnTabNavigate, [&]( const Event* ) {
if ( !mToggle->hasClass( "enabled" ) ) {
mToggle->addClass( "enabled" );
mReplaceBox->addClass( "enabled" );
}
mReplaceInput->setFocus();
} );
mReplaceInput->addEventListener( Event::OnTabNavigate,
[&]( const Event* ) { mFindInput->setFocus(); } );
mDataBinds.emplace_back( std::unique_ptr<UIDataBind<bool>>(
new UIDataBind<bool>( &mSearchState.caseSensitive, mCaseSensitive ) ) );
mDataBinds.emplace_back( std::unique_ptr<UIDataBind<bool>>(
new UIDataBind<bool>( &mSearchState.wholeWord, mWholeWord ) ) );
mDataBinds.emplace_back( std::unique_ptr<UIDataBind<bool>>(
new UIDataBind<bool>( &mSearchState.escapeSequences, mEscapeSequences ) ) );
UIDataBind<TextDocument::FindReplaceType>::Converter luaPatternConverter(
[]( const UIDataBind<TextDocument::FindReplaceType>* databind,
TextDocument::FindReplaceType& val, const std::string& str ) -> bool {
val = StyleSheetProperty( databind->getPropertyDefinition(), str ).asBool()
? TextDocument::FindReplaceType::LuaPattern
: TextDocument::FindReplaceType::Normal;
return true;
},
[]( const UIDataBind<TextDocument::FindReplaceType>*, std::string& str,
const TextDocument::FindReplaceType& val ) -> bool {
str = val == TextDocument::FindReplaceType::LuaPattern ? "true" : "false";
return true;
} );
mPatternBind = std::unique_ptr<UIDataBind<TextDocument::FindReplaceType>>(
new UIDataBind<TextDocument::FindReplaceType>( &mSearchState.type, mLuaPattern,
luaPatternConverter ) );
setVisible( false );
runOnMainThread( [&] { mReady = true; } );
@@ -267,7 +329,7 @@ UIDocFindReplace::UIDocFindReplace( UIWidget* parent, const std::shared_ptr<Doc:
} );
}
void UIDocFindReplace::show() {
void UIDocFindReplace::show( bool expanded ) {
if ( !mReady ) {
runOnMainThread( [&] { show(); } );
return;
@@ -283,25 +345,19 @@ void UIDocFindReplace::show() {
UICodeEditor* editor =
getParent()->isType( UI_TYPE_CODEEDITOR ) ? getParent()->asType<UICodeEditor>() : nullptr;
mSearchState.range = TextRange();
mSearchState.caseSensitive = mCaseSensitive->isSelected();
mSearchState.wholeWord = mWholeWord->isSelected();
mSearchState.escapeSequences = mEscapeSequences->isSelected();
mSearchState.type = mLuaPattern->isSelected() ? TextDocument::FindReplaceType::LuaPattern
: TextDocument::FindReplaceType::Normal;
mFindInput->getDocument().selectAll();
mFindInput->setFocus();
const TextDocument& doc = *mDoc;
if ( mDoc->getSelection().hasSelection() ) {
String text = mDoc->getSelectedText();
if ( doc.getSelection().hasSelection() ) {
String text = doc.getSelectedText();
if ( !mDoc->getSelection().inSameLine() )
mSearchState.range = mDoc->getSelection( true );
if ( !doc.getSelection().inSameLine() )
mSearchState.range = doc.getSelection( true );
if ( !text.empty() && doc.getSelection().inSameLine() ) {
if ( !text.empty() && mDoc->getSelection().inSameLine() ) {
mFindInput->setText( text );
mFindInput->getDocument().selectAll();
} else if ( !mFindInput->getText().empty() ) {
@@ -311,10 +367,18 @@ void UIDocFindReplace::show() {
mSearchState.text = mFindInput->getText();
if ( !expanded ) {
mToggle->removeClass( "enabled" );
mReplaceBox->removeClass( "enabled" );
} else {
mToggle->addClass( "enabled" );
mReplaceBox->addClass( "enabled" );
}
if ( editor ) {
editor->setHighlightTextRange( mSearchState.range );
editor->setHighlightWord( mSearchState.text );
editor->getDocument().setActiveClient( editor );
mDoc->setActiveClient( editor );
}
}
@@ -342,12 +406,10 @@ bool UIDocFindReplace::findPrevText( SearchState& search ) {
search.text = mLastSearch;
mLastSearch = search.text;
TextDocument& doc = *mDoc;
TextRange range = doc.getDocRange();
TextPosition from = doc.getSelection( true ).start();
TextRange range = mDoc->getDocRange();
TextPosition from = mDoc->getSelection( true ).start();
if ( search.range.isValid() ) {
range = doc.sanitizeRange( search.range ).normalized();
range = mDoc->sanitizeRange( search.range ).normalized();
from = from < range.start() ? range.start() : from;
}
@@ -355,17 +417,17 @@ bool UIDocFindReplace::findPrevText( SearchState& search ) {
if ( search.escapeSequences )
txt.unescape();
TextRange found = doc.findLast( txt, from, search.caseSensitive, search.wholeWord, search.type,
search.range );
TextRange found = mDoc->findLast( txt, from, search.caseSensitive, search.wholeWord,
search.type, search.range );
if ( found.isValid() ) {
doc.setSelection( found );
mDoc->setSelection( found );
mFindInput->removeClass( "error" );
return true;
} else {
found = doc.findLast( txt, range.end(), search.caseSensitive, search.wholeWord, search.type,
range );
found = mDoc->findLast( txt, range.end(), search.caseSensitive, search.wholeWord,
search.type, range );
if ( found.isValid() ) {
doc.setSelection( found );
mDoc->setSelection( found );
mFindInput->removeClass( "error" );
return true;
}
@@ -379,12 +441,11 @@ bool UIDocFindReplace::findNextText( SearchState& search ) {
search.text = mLastSearch;
mLastSearch = search.text;
TextDocument& doc = *mDoc;
TextRange range = doc.getDocRange();
TextPosition from = doc.getSelection( true ).end();
TextRange range = mDoc->getDocRange();
TextPosition from = mDoc->getSelection( true ).end();
if ( search.range.isValid() ) {
range = doc.sanitizeRange( search.range ).normalized();
range = mDoc->sanitizeRange( search.range ).normalized();
from = from < range.start() ? range.start() : from;
}
@@ -393,16 +454,16 @@ bool UIDocFindReplace::findNextText( SearchState& search ) {
txt.unescape();
TextRange found =
doc.find( txt, from, search.caseSensitive, search.wholeWord, search.type, range );
mDoc->find( txt, from, search.caseSensitive, search.wholeWord, search.type, range );
if ( found.isValid() ) {
doc.setSelection( found.reversed() );
mDoc->setSelection( found.reversed() );
mFindInput->removeClass( "error" );
return true;
} else {
found = doc.find( txt, range.start(), search.caseSensitive, search.wholeWord, search.type,
range );
found = mDoc->find( txt, range.start(), search.caseSensitive, search.wholeWord, search.type,
range );
if ( found.isValid() ) {
doc.setSelection( found.reversed() );
mDoc->setSelection( found.reversed() );
mFindInput->removeClass( "error" );
return true;
}
@@ -416,10 +477,9 @@ int UIDocFindReplace::replaceAll( SearchState& search, const String& replace ) {
search.text = mLastSearch;
if ( search.text.empty() )
return 0;
TextDocument& doc = *mDoc;
mLastSearch = search.text;
TextPosition startedPosition = doc.getSelection().start();
TextPosition startedPosition = mDoc->getSelection().start();
String txt( search.text );
String repl( replace );
@@ -428,9 +488,9 @@ int UIDocFindReplace::replaceAll( SearchState& search, const String& replace ) {
repl.unescape();
}
int count = doc.replaceAll( txt, repl, search.caseSensitive, search.wholeWord, search.type,
search.range );
doc.setSelection( startedPosition );
int count = mDoc->replaceAll( txt, repl, search.caseSensitive, search.wholeWord, search.type,
search.range );
mDoc->setSelection( startedPosition );
return count;
}
@@ -443,7 +503,6 @@ bool UIDocFindReplace::findAndReplace( SearchState& search, const String& replac
search.text = mLastSearch;
if ( search.text.empty() )
return false;
TextDocument& doc = *mDoc;
mLastSearch = search.text;
@@ -454,7 +513,7 @@ bool UIDocFindReplace::findAndReplace( SearchState& search, const String& replac
repl.unescape();
}
if ( doc.hasSelection() && doc.getSelectedText() == txt ) {
if ( mDoc->hasSelection() && mDoc->getSelectedText() == txt ) {
mDoc->replaceSelection( repl );
return true;
} else {

View File

@@ -225,6 +225,8 @@ std::string UICheckBox::getPropertyString( const PropertyDefinition* propertyDef
switch ( propertyDef->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Checked:
case PropertyId::Value:
return isChecked() ? "true" : "false";
default:
return UITextView::getPropertyString( propertyDef, propertyIndex );
@@ -237,6 +239,8 @@ bool UICheckBox::applyProperty( const StyleSheetProperty& attribute ) {
switch ( attribute.getPropertyDefinition()->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Checked:
case PropertyId::Value:
setChecked( attribute.asBool() );
break;
default:

View File

@@ -37,9 +37,11 @@ void UIEventDispatcher::inputCallback( InputEvent* Event ) {
void UIEventDispatcher::checkTabPress( const Uint32& KeyCode ) {
eeASSERT( NULL != mFocusNode );
Window::Window* win = mFocusNode->getSceneNode()->getWindow();
if ( KeyCode == KEY_TAB && mFocusNode->isWidget() && NULL != win && !mJustGainedFocus ) {
mFocusNode->asType<UIWidget>()->onTabPress();
if ( KeyCode == KEY_TAB ) {
Window::Window* win = mFocusNode->getSceneNode()->getWindow();
if ( mFocusNode->isWidget() && NULL != win && !mJustGainedFocus ) {
mFocusNode->asType<UIWidget>()->onTabPress();
}
}
}

View File

@@ -122,4 +122,40 @@ void UIMenuCheckBox::onStateChange() {
setActive( mActive );
}
bool UIMenuCheckBox::applyProperty( const StyleSheetProperty& attribute ) {
bool attributeSet = true;
if ( attribute.getPropertyDefinition() == NULL ) {
return false;
}
switch ( attribute.getPropertyDefinition()->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Checked:
case PropertyId::Value:
setActive( attribute.asBool() );
break;
default:
attributeSet = UIPushButton::applyProperty( attribute );
break;
}
return attributeSet;
}
std::string UIMenuCheckBox::getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex ) const {
if ( NULL == propertyDef )
return "";
switch ( propertyDef->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Checked:
case PropertyId::Value:
return isActive() ? "true" : "false";
default:
return UIPushButton::getPropertyString( propertyDef, propertyIndex );
}
}
}} // namespace EE::UI

View File

@@ -135,4 +135,35 @@ void UIMenuRadioButton::onStateChange() {
setActive( mActive );
}
std::string UIMenuRadioButton::getPropertyString( const PropertyDefinition* propertyDef,
const Uint32& propertyIndex ) const {
if ( NULL == propertyDef )
return "";
switch ( propertyDef->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Value:
return isActive() ? "true" : "false";
break;
default:
return UIMenuItem::getPropertyString( propertyDef, propertyIndex );
}
}
bool UIMenuRadioButton::applyProperty( const StyleSheetProperty& attribute ) {
if ( !checkPropertyDefinition( attribute ) )
return false;
switch ( attribute.getPropertyDefinition()->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Value:
setActive( attribute.asBool() );
break;
default:
return UIMenuItem::applyProperty( attribute );
}
return true;
}
}} // namespace EE::UI

View File

@@ -280,6 +280,7 @@ std::string UIRadioButton::getPropertyString( const PropertyDefinition* property
switch ( propertyDef->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Value:
return isActive() ? "true" : "false";
break;
default:
@@ -293,6 +294,7 @@ bool UIRadioButton::applyProperty( const StyleSheetProperty& attribute ) {
switch ( attribute.getPropertyDefinition()->getPropertyId() ) {
case PropertyId::Selected:
case PropertyId::Value:
setActive( attribute.asBool() );
break;
default:

View File

@@ -38,6 +38,7 @@ void UISelectButton::select() {
messagePost( &tMsg );
sendCommonEvent( Event::OnSelectionChanged );
onValueChange();
}
}
@@ -50,6 +51,7 @@ void UISelectButton::unselect() {
mNodeFlags &= ~NODE_FLAG_SELECTED;
sendCommonEvent( Event::OnSelectionChanged );
onValueChange();
}
popState( UIState::StateSelected );
@@ -84,6 +86,7 @@ bool UISelectButton::applyProperty( const StyleSheetProperty& attribute ) {
setSelectOnClick( attribute.asBool() );
break;
case PropertyId::Selected:
case PropertyId::Value:
setSelected( attribute.asBool() );
break;
default:
@@ -103,6 +106,7 @@ std::string UISelectButton::getPropertyString( const PropertyDefinition* propert
case PropertyId::SelectOnClick:
return hasSelectOnClick() ? "true" : "false";
case PropertyId::Selected:
case PropertyId::Value:
return isSelected() ? "true" : "false";
default:
return UIPushButton::getPropertyString( propertyDef, propertyIndex );

View File

@@ -260,6 +260,14 @@ void UIWidget::onChildCountChange( Node* child, const bool& removed ) {
}
}
Uint32 UIWidget::onKeyDown( const KeyEvent& event ) {
if ( event.getKeyCode() == KEY_TAB && isTabStop() ) {
Node::onKeyDown( event );
return 1;
}
return Node::onKeyDown( event );
}
Vector2f UIWidget::getTooltipPosition() {
EventDispatcher* eventDispatcher = getEventDispatcher();
UIThemeManager* themeManager = getUISceneNode()->getUIThemeManager();
@@ -1774,6 +1782,10 @@ bool UIWidget::isTabStop() const {
return ( mFlags & UI_TAB_STOP ) != 0;
}
void UIWidget::setTabStop() {
mFlags |= UI_TAB_STOP;
}
UIWidget* UIWidget::getNextWidget() const {
UIWidget* found = NULL;
UIWidget* possible = NULL;
@@ -1844,6 +1856,8 @@ void UIWidget::onTabPress() {
node->setFocus();
sendCommonEvent( Event::OnTabNavigate );
}
} else {
sendCommonEvent( Event::OnTabNavigate );
}
}

View File

@@ -32,76 +32,74 @@ void DocSearchController::initSearchBar(
{ mApp->getKeybind( "open-global-search" ), "open-global-search" } } );
kbind.addKeybindsStringUnordered( keybindings );
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
findInput->setEscapePastedText( true );
UITextInput* replaceInput = mSearchBarLayout->find<UITextInput>( "search_replace" );
UICheckBox* caseSensitiveChk = mSearchBarLayout->find<UICheckBox>( "case_sensitive" );
UICheckBox* escapeSequenceChk = mSearchBarLayout->find<UICheckBox>( "escape_sequence" );
UICheckBox* wholeWordChk = mSearchBarLayout->find<UICheckBox>( "whole_word" );
UICheckBox* luaPatternChk = mSearchBarLayout->find<UICheckBox>( "lua_pattern" );
mFindInput = mSearchBarLayout->find<UITextInput>( "search_find" );
mFindInput->setEscapePastedText( true );
mReplaceInput = mSearchBarLayout->find<UITextInput>( "search_replace" );
mCaseSensitiveChk = mSearchBarLayout->find<UICheckBox>( "case_sensitive" );
mEscapeSequenceChk = mSearchBarLayout->find<UICheckBox>( "escape_sequence" );
mWholeWordChk = mSearchBarLayout->find<UICheckBox>( "whole_word" );
mLuaPatternChk = mSearchBarLayout->find<UICheckBox>( "lua_pattern" );
UIPushButton* replaceAllButton = mSearchBarLayout->find<UIPushButton>( "replace_all" );
UIPushButton* findPrevButton = mSearchBarLayout->find<UIPushButton>( "find_prev" );
UIPushButton* findNextButton = mSearchBarLayout->find<UIPushButton>( "find_next" );
UIPushButton* replaceButton = mSearchBarLayout->find<UIPushButton>( "replace" );
UIPushButton* findReplaceButton = mSearchBarLayout->find<UIPushButton>( "replace_find" );
caseSensitiveChk->setChecked( searchBarConfig.caseSensitive );
luaPatternChk->setChecked( searchBarConfig.luaPattern );
wholeWordChk->setChecked( searchBarConfig.wholeWord );
escapeSequenceChk->setChecked( searchBarConfig.escapeSequence );
UIWidget* closeButton = mSearchBarLayout->find<UIWidget>( "searchbar_close" );
mCaseSensitiveChk->setChecked( searchBarConfig.caseSensitive );
mLuaPatternChk->setChecked( searchBarConfig.luaPattern );
mWholeWordChk->setChecked( searchBarConfig.wholeWord );
mEscapeSequenceChk->setChecked( searchBarConfig.escapeSequence );
luaPatternChk->setTooltipText( kbind.getCommandKeybindString( "toggle-lua-pattern" ) );
caseSensitiveChk->setTooltipText( kbind.getCommandKeybindString( "change-case" ) );
wholeWordChk->setTooltipText( kbind.getCommandKeybindString( "change-whole-word" ) );
mLuaPatternChk->setTooltipText( kbind.getCommandKeybindString( "toggle-lua-pattern" ) );
mCaseSensitiveChk->setTooltipText( kbind.getCommandKeybindString( "change-case" ) );
mWholeWordChk->setTooltipText( kbind.getCommandKeybindString( "change-whole-word" ) );
std::string kbindEscape = kbind.getCommandKeybindString( "change-escape-sequence" );
if ( !kbindEscape.empty() )
escapeSequenceChk->setTooltipText( escapeSequenceChk->getTooltipText() + " (" +
mEscapeSequenceChk->setTooltipText( mEscapeSequenceChk->getTooltipText() + " (" +
kbindEscape + ")" );
caseSensitiveChk->addEventListener(
Event::OnValueChange, [&, caseSensitiveChk]( const Event* ) {
mSearchState.caseSensitive = caseSensitiveChk->isChecked();
} );
escapeSequenceChk->addEventListener(
Event::OnValueChange, [&, escapeSequenceChk]( const Event* ) {
mSearchState.escapeSequences = escapeSequenceChk->isChecked();
} );
wholeWordChk->addEventListener( Event::OnValueChange, [&, wholeWordChk]( const Event* ) {
mSearchState.wholeWord = wholeWordChk->isChecked();
mCaseSensitiveChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.caseSensitive = mCaseSensitiveChk->isChecked();
} );
luaPatternChk->addEventListener( Event::OnValueChange, [&, luaPatternChk]( const Event* ) {
mSearchState.type = luaPatternChk->isChecked() ? TextDocument::FindReplaceType::LuaPattern
mEscapeSequenceChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.escapeSequences = mEscapeSequenceChk->isChecked();
} );
mWholeWordChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.wholeWord = mWholeWordChk->isChecked();
} );
mLuaPatternChk->addEventListener( Event::OnValueChange, [&]( const Event* ) {
mSearchState.type = mLuaPatternChk->isChecked() ? TextDocument::FindReplaceType::LuaPattern
: TextDocument::FindReplaceType::Normal;
} );
findInput->addEventListener( Event::OnTextChanged, [&, findInput]( const Event* ) {
mFindInput->addEventListener( Event::OnTextChanged, [&]( const Event* ) {
if ( mSearchState.editor && mEditorSplitter->editorExists( mSearchState.editor ) ) {
mSearchState.text = findInput->getText();
mSearchState.text = mFindInput->getText();
mSearchState.editor->setHighlightWord( mSearchState.text );
if ( !mSearchState.text.empty() ) {
mSearchState.editor->getDocument().setSelection( { 0, 0 } );
if ( !findNextText( mSearchState ) ) {
findInput->addClass( "error" );
mFindInput->addClass( "error" );
} else {
findInput->removeClass( "error" );
mFindInput->removeClass( "error" );
}
} else {
findInput->removeClass( "error" );
mFindInput->removeClass( "error" );
mSearchState.editor->getDocument().setSelection(
mSearchState.editor->getDocument().getSelection().start() );
}
}
} );
findInput->addEventListener(
Event::OnTextPasted, [&, findInput, escapeSequenceChk]( const Event* ) {
if ( findInput->getUISceneNode()->getWindow()->getClipboard()->getText().find( '\n' ) !=
String::InvalidPos ) {
if ( !escapeSequenceChk->isChecked() )
escapeSequenceChk->setChecked( true );
}
} );
mFindInput->addEventListener( Event::OnTextPasted, [&]( const Event* ) {
if ( mFindInput->getUISceneNode()->getWindow()->getClipboard()->getText().find( '\n' ) !=
String::InvalidPos ) {
if ( !mEscapeSequenceChk->isChecked() )
mEscapeSequenceChk->setChecked( true );
}
} );
mSearchBarLayout->addCommand( "close-searchbar", [&] {
hideSearchBar();
if ( mEditorSplitter->getCurWidget() )
@@ -114,43 +112,39 @@ void DocSearchController::initSearchBar(
}
} );
mSearchBarLayout->addCommand( "repeat-find", [this] { findNextText( mSearchState ); } );
mSearchBarLayout->addCommand( "replace-all", [this, replaceInput] {
size_t count = replaceAll( mSearchState, replaceInput->getText() );
mSearchBarLayout->addCommand( "replace-all", [this] {
size_t count = replaceAll( mSearchState, mReplaceInput->getText() );
mApp->getNotificationCenter()->addNotification(
String::format( "Replaced %zu occurrences.", count ) );
replaceInput->setFocus();
} );
mSearchBarLayout->addCommand( "find-and-replace", [this, replaceInput] {
findAndReplace( mSearchState, replaceInput->getText() );
mReplaceInput->setFocus();
} );
mSearchBarLayout->addCommand(
"find-and-replace", [this] { findAndReplace( mSearchState, mReplaceInput->getText() ); } );
mSearchBarLayout->addCommand( "find-prev", [this] { findPrevText( mSearchState ); } );
mSearchBarLayout->addCommand( "replace-selection", [this, replaceInput] {
replaceSelection( mSearchState, replaceInput->getText() );
mSearchBarLayout->addCommand( "replace-selection", [this] {
replaceSelection( mSearchState, mReplaceInput->getText() );
} );
mSearchBarLayout->addCommand( "change-case", [&, caseSensitiveChk] {
caseSensitiveChk->setChecked( !caseSensitiveChk->isChecked() );
} );
mSearchBarLayout->addCommand( "change-whole-word", [&, wholeWordChk] {
wholeWordChk->setChecked( !wholeWordChk->isChecked() );
} );
mSearchBarLayout->addCommand( "change-escape-sequence", [&, escapeSequenceChk] {
escapeSequenceChk->setChecked( !escapeSequenceChk->isChecked() );
} );
mSearchBarLayout->addCommand( "toggle-lua-pattern", [&, luaPatternChk] {
luaPatternChk->setChecked( !luaPatternChk->isChecked() );
mSearchBarLayout->addCommand(
"change-case", [&] { mCaseSensitiveChk->setChecked( !mCaseSensitiveChk->isChecked() ); } );
mSearchBarLayout->addCommand( "change-whole-word",
[&] { mWholeWordChk->setChecked( !mWholeWordChk->isChecked() ); } );
mSearchBarLayout->addCommand( "change-escape-sequence", [&] {
mEscapeSequenceChk->setChecked( !mEscapeSequenceChk->isChecked() );
} );
mSearchBarLayout->addCommand(
"toggle-lua-pattern", [&] { mLuaPatternChk->setChecked( !mLuaPatternChk->isChecked() ); } );
mSearchBarLayout->addCommand( "open-global-search", [&] { mApp->showGlobalSearch( false ); } );
addReturnListener( findInput, "repeat-find" );
addReturnListener( replaceInput, "find-and-replace" );
addReturnListener( mFindInput, "repeat-find" );
addReturnListener( mReplaceInput, "find-and-replace" );
addClickListener( findPrevButton, "find-prev" );
addClickListener( findNextButton, "repeat-find" );
addClickListener( replaceButton, "replace-selection" );
addClickListener( findReplaceButton, "find-and-replace" );
addClickListener( replaceAllButton, "replace-all" );
addClickListener( mSearchBarLayout->find<UIWidget>( "searchbar_close" ), "close-searchbar" );
replaceInput->addEventListener( Event::OnTabNavigate,
[findInput]( const Event* ) { findInput->setFocus(); } );
addClickListener( closeButton, "close-searchbar" );
mReplaceInput->addEventListener( Event::OnTabNavigate,
[&]( const Event* ) { mFindInput->setFocus(); } );
}
void DocSearchController::showFindView() {
@@ -162,19 +156,15 @@ void DocSearchController::showFindView() {
UICodeEditor* editor = mEditorSplitter->getCurEditor();
mSearchState.editor = editor;
mSearchState.range = TextRange();
mSearchState.caseSensitive =
mSearchBarLayout->find<UICheckBox>( "case_sensitive" )->isChecked();
mSearchState.wholeWord = mSearchBarLayout->find<UICheckBox>( "whole_word" )->isChecked();
mSearchState.escapeSequences =
mSearchBarLayout->find<UICheckBox>( "escape_sequence" )->isChecked();
mSearchState.type = mSearchBarLayout->find<UICheckBox>( "lua_pattern" )->isChecked()
? TextDocument::FindReplaceType::LuaPattern
: TextDocument::FindReplaceType::Normal;
mSearchState.caseSensitive = mCaseSensitiveChk->isChecked();
mSearchState.wholeWord = mWholeWordChk->isChecked();
mSearchState.escapeSequences = mEscapeSequenceChk->isChecked();
mSearchState.type = mLuaPatternChk->isChecked() ? TextDocument::FindReplaceType::LuaPattern
: TextDocument::FindReplaceType::Normal;
mSearchBarLayout->setEnabled( true )->setVisible( true );
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
findInput->getDocument().selectAll();
findInput->setFocus();
mFindInput->getDocument().selectAll();
mFindInput->setFocus();
const TextDocument& doc = editor->getDocument();
@@ -185,13 +175,13 @@ void DocSearchController::showFindView() {
mSearchState.range = doc.getSelection( true );
if ( !text.empty() && doc.getSelection().inSameLine() ) {
findInput->setText( text );
findInput->getDocument().selectAll();
} else if ( !findInput->getText().empty() ) {
findInput->getDocument().selectAll();
mFindInput->setText( text );
mFindInput->getDocument().selectAll();
} else if ( !mFindInput->getText().empty() ) {
mFindInput->getDocument().selectAll();
}
}
mSearchState.text = findInput->getText();
mSearchState.text = mFindInput->getText();
editor->setHighlightTextRange( mSearchState.range );
editor->setHighlightWord( mSearchState.text );
editor->getDocument().setActiveClient( editor );
@@ -203,7 +193,6 @@ bool DocSearchController::findPrevText( SearchState& search ) {
if ( !search.editor || !mEditorSplitter->editorExists( search.editor ) || search.text.empty() )
return false;
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
search.editor->getDocument().setActiveClient( search.editor );
mLastSearch = search.text;
TextDocument& doc = search.editor->getDocument();
@@ -222,18 +211,18 @@ bool DocSearchController::findPrevText( SearchState& search ) {
search.range );
if ( found.isValid() ) {
doc.setSelection( found );
findInput->removeClass( "error" );
mFindInput->removeClass( "error" );
return true;
} else {
found = doc.findLast( txt, range.end(), search.caseSensitive, search.wholeWord, search.type,
range );
if ( found.isValid() ) {
doc.setSelection( found );
findInput->removeClass( "error" );
mFindInput->removeClass( "error" );
return true;
}
}
findInput->addClass( "error" );
mFindInput->addClass( "error" );
return false;
}
@@ -243,7 +232,6 @@ bool DocSearchController::findNextText( SearchState& search ) {
if ( !search.editor || !mEditorSplitter->editorExists( search.editor ) || search.text.empty() )
return false;
UITextInput* findInput = mSearchBarLayout->find<UITextInput>( "search_find" );
search.editor->getDocument().setActiveClient( search.editor );
mLastSearch = search.text;
TextDocument& doc = search.editor->getDocument();
@@ -262,18 +250,18 @@ bool DocSearchController::findNextText( SearchState& search ) {
doc.find( txt, from, search.caseSensitive, search.wholeWord, search.type, range );
if ( found.isValid() ) {
doc.setSelection( found.reversed() );
findInput->removeClass( "error" );
mFindInput->removeClass( "error" );
return true;
} else {
found = doc.find( txt, range.start(), search.caseSensitive, search.wholeWord, search.type,
range );
if ( found.isValid() ) {
doc.setSelection( found.reversed() );
findInput->removeClass( "error" );
mFindInput->removeClass( "error" );
return true;
}
}
findInput->addClass( "error" );
mFindInput->addClass( "error" );
return false;
}
@@ -360,15 +348,11 @@ SearchState& DocSearchController::getSearchState() {
}
SearchBarConfig DocSearchController::getSearchBarConfig() const {
UICheckBox* caseSensitiveChk = mSearchBarLayout->find<UICheckBox>( "case_sensitive" );
UICheckBox* escapeSequenceChk = mSearchBarLayout->find<UICheckBox>( "escape_sequence" );
UICheckBox* wholeWordChk = mSearchBarLayout->find<UICheckBox>( "whole_word" );
UICheckBox* luaPatternChk = mSearchBarLayout->find<UICheckBox>( "lua_pattern" );
SearchBarConfig searchBarConfig;
searchBarConfig.caseSensitive = caseSensitiveChk->isChecked();
searchBarConfig.luaPattern = luaPatternChk->isChecked();
searchBarConfig.wholeWord = wholeWordChk->isChecked();
searchBarConfig.escapeSequence = escapeSequenceChk->isChecked();
searchBarConfig.caseSensitive = mCaseSensitiveChk->isChecked();
searchBarConfig.luaPattern = mLuaPatternChk->isChecked();
searchBarConfig.wholeWord = mWholeWordChk->isChecked();
searchBarConfig.escapeSequence = mEscapeSequenceChk->isChecked();
return searchBarConfig;
}

View File

@@ -27,11 +27,16 @@ class UISearchBar;
class DocSearchController {
public:
static std::unordered_map<std::string, std::string> getDefaultKeybindings() {
return { { "mod+g", "repeat-find" }, { "escape", "close-searchbar" },
{ "mod+r", "replace-selection" }, { "mod+shift+n", "find-and-replace" },
{ "mod+shift+r", "replace-all" }, { "mod+s", "change-case" },
{ "mod+w", "change-whole-word" }, { "mod+l", "toggle-lua-pattern" },
{ "mod+e", "change-escape-sequence" } };
return { { "mod+g", "repeat-find" },
{ "escape", "close-searchbar" },
{ "mod+r", "replace-selection" },
{ "mod+shift+n", "find-and-replace" },
{ "mod+shift+r", "replace-all" },
{ "mod+s", "change-case" },
{ "mod+w", "change-whole-word" },
{ "mod+l", "toggle-lua-pattern" },
{ "mod+e", "change-escape-sequence" },
{ "mod+shift+g", "find-prev" } };
}
DocSearchController( UICodeEditorSplitter*, App* app );
@@ -62,7 +67,13 @@ class DocSearchController {
protected:
UICodeEditorSplitter* mEditorSplitter{ nullptr };
UITextInput* mFindInput{ nullptr };
UITextInput* mReplaceInput{ nullptr };
UISearchBar* mSearchBarLayout{ nullptr };
UICheckBox* mCaseSensitiveChk{ nullptr };
UICheckBox* mEscapeSequenceChk{ nullptr };
UICheckBox* mWholeWordChk{ nullptr };
UICheckBox* mLuaPatternChk{ nullptr };
App* mApp{ nullptr };
SearchState mSearchState;
String mLastSearch;