1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-22 01:34:21 +00:00

iPhone on-screen keyboard support, when a TextEditor or CodeEditor is focused.

This commit is contained in:
Julian Storer 2010-03-22 17:25:45 +00:00
parent 7bc8db2ff4
commit 49320b25d2
20 changed files with 375 additions and 114 deletions

View file

@ -52245,6 +52245,12 @@ void TextEditor::insertTextAtCaret (const String& newText_)
if (allowedCharacters.isNotEmpty())
newText = newText.retainCharacters (allowedCharacters);
if ((! returnKeyStartsNewLine) && newText == T("\n"))
{
returnPressed();
return;
}
if (! isMultiLine())
newText = newText.replaceCharacters (T("\r\n"), T(" "));
else
@ -52658,11 +52664,7 @@ bool TextEditor::keyPressed (const KeyPress& key)
else if (key == KeyPress::returnKey)
{
newTransaction();
if (returnKeyStartsNewLine)
insertTextAtCaret (T("\n"));
else
returnPressed();
insertTextAtCaret (T("\n"));
}
else if (key.isKeyCode (KeyPress::escapeKey))
{
@ -77406,7 +77408,8 @@ TooltipWindow::TooltipWindow (Component* const parentComponent,
lastComponentUnderMouse (0),
changedCompsSinceShown (true)
{
startTimer (123);
if (Desktop::getInstance().getMainMouseSource().canHover())
startTimer (123);
setAlwaysOnTop (true);
setOpaque (true);
@ -114411,6 +114414,9 @@ void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
#endif
}
#undef max
#undef min
#ifdef _MSC_VER
#pragma warning (pop)
#endif
@ -114418,7 +114424,7 @@ void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
BEGIN_JUCE_NAMESPACE
static const char* const flacFormatName = "FLAC file";
static const tchar* const flacExtensions[] = { T(".flac"), 0 };
static const juce_wchar* const flacExtensions[] = { T(".flac"), 0 };
class FlacReader : public AudioFormatReader
{
@ -114580,34 +114586,34 @@ public:
static FlacNamespace::FLAC__StreamDecoderReadStatus readCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__byte buffer[], size_t* bytes, void* client_data)
{
using namespace FlacNamespace;
*bytes = (unsigned int) ((const FlacReader*) client_data)->input->read (buffer, (int) *bytes);
*bytes = (size_t) static_cast <const FlacReader*> (client_data)->input->read (buffer, (int) *bytes);
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
static FlacNamespace::FLAC__StreamDecoderSeekStatus seekCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64 absolute_byte_offset, void* client_data)
{
using namespace FlacNamespace;
((const FlacReader*) client_data)->input->setPosition ((int) absolute_byte_offset);
static_cast <const FlacReader*> (client_data)->input->setPosition ((int) absolute_byte_offset);
return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
}
static FlacNamespace::FLAC__StreamDecoderTellStatus tellCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* absolute_byte_offset, void* client_data)
{
using namespace FlacNamespace;
*absolute_byte_offset = ((const FlacReader*) client_data)->input->getPosition();
*absolute_byte_offset = static_cast <const FlacReader*> (client_data)->input->getPosition();
return FLAC__STREAM_DECODER_TELL_STATUS_OK;
}
static FlacNamespace::FLAC__StreamDecoderLengthStatus lengthCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__uint64* stream_length, void* client_data)
{
using namespace FlacNamespace;
*stream_length = ((const FlacReader*) client_data)->input->getTotalLength();
*stream_length = static_cast <const FlacReader*> (client_data)->input->getTotalLength();
return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
}
static FlacNamespace::FLAC__bool eofCallback_ (const FlacNamespace::FLAC__StreamDecoder*, void* client_data)
{
return ((const FlacReader*) client_data)->input->isExhausted();
return static_cast <const FlacReader*> (client_data)->input->isExhausted();
}
static FlacNamespace::FLAC__StreamDecoderWriteStatus writeCallback_ (const FlacNamespace::FLAC__StreamDecoder*,
@ -114616,7 +114622,7 @@ public:
void* client_data)
{
using namespace FlacNamespace;
((FlacReader*) client_data)->useSamples (buffer, frame->header.blocksize);
static_cast <FlacReader*> (client_data)->useSamples (buffer, frame->header.blocksize);
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
@ -114624,7 +114630,7 @@ public:
const FlacNamespace::FLAC__StreamMetadata* metadata,
void* client_data)
{
((FlacReader*) client_data)->useMetadata (metadata->data.stream_info);
static_cast <FlacReader*> (client_data)->useMetadata (metadata->data.stream_info);
}
static void errorCallback_ (const FlacNamespace::FLAC__StreamDecoder*, FlacNamespace::FLAC__StreamDecoderErrorStatus, void*)
@ -114780,7 +114786,7 @@ public:
void* client_data)
{
using namespace FlacNamespace;
return ((FlacWriter*) client_data)->writeData (buffer, (int) bytes)
return static_cast <FlacWriter*> (client_data)->writeData (buffer, (int) bytes)
? FLAC__STREAM_ENCODER_WRITE_STATUS_OK
: FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
}
@ -114797,15 +114803,13 @@ public:
if (client_data == 0)
return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
*absolute_byte_offset = (FLAC__uint64) ((FlacWriter*) client_data)->output->getPosition();
*absolute_byte_offset = (FLAC__uint64) static_cast <FlacWriter*> (client_data)->output->getPosition();
return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
}
static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder*,
const FlacNamespace::FLAC__StreamMetadata* metadata,
void* client_data)
static void encodeMetadataCallback (const FlacNamespace::FLAC__StreamEncoder*, const FlacNamespace::FLAC__StreamMetadata* metadata, void* client_data)
{
((FlacWriter*) client_data)->writeMetaData (metadata);
static_cast <FlacWriter*> (client_data)->writeMetaData (metadata);
}
juce_UseDebuggingNewOperator
@ -114821,7 +114825,7 @@ private:
};
FlacAudioFormat::FlacAudioFormat()
: AudioFormat (TRANS (flacFormatName), (const tchar**) flacExtensions)
: AudioFormat (TRANS (flacFormatName), (const juce_wchar**) flacExtensions)
{
}
@ -114859,7 +114863,7 @@ bool FlacAudioFormat::isCompressed()
AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in,
const bool deleteStreamIfOpeningFails)
{
ScopedPointer <FlacReader> r (new FlacReader (in));
ScopedPointer<FlacReader> r (new FlacReader (in));
if (r->sampleRate != 0)
return r.release();
@ -114879,10 +114883,7 @@ AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out,
{
if (getPossibleBitDepths().contains (bitsPerSample))
{
ScopedPointer <FlacWriter> w (new FlacWriter (out,
sampleRate,
numberOfChannels,
bitsPerSample));
ScopedPointer<FlacWriter> w (new FlacWriter (out, sampleRate, numberOfChannels, bitsPerSample));
if (w->ok)
return w.release();
@ -171166,10 +171167,13 @@ void _vorbis_apply_window(float *d,int *winno,long *blocksizes,
#endif
}
#undef max
#undef min
BEGIN_JUCE_NAMESPACE
static const char* const oggFormatName = "Ogg-Vorbis file";
static const tchar* const oggExtensions[] = { T(".ogg"), 0 };
static const juce_wchar* const oggExtensions[] = { T(".ogg"), 0 };
class OggReader : public AudioFormatReader
{
@ -171471,7 +171475,7 @@ public:
};
OggVorbisAudioFormat::OggVorbisAudioFormat()
: AudioFormat (TRANS (oggFormatName), (const tchar**) oggExtensions)
: AudioFormat (TRANS (oggFormatName), (const juce_wchar**) oggExtensions)
{
}
@ -188337,6 +188341,9 @@ jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
#endif
}
#undef max
#undef min
#if JUCE_MSVC
#pragma warning (pop)
#endif
@ -210929,6 +210936,9 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
#endif
}
#undef max
#undef min
#ifdef _MSC_VER
#pragma warning (pop)
#endif
@ -210943,11 +210953,14 @@ namespace PNGHelpers
{
using namespace pnglibNamespace;
static void readCallback (png_structp pngReadStruct, png_bytep data, png_size_t length)
static void readCallback (png_structp png, png_bytep data, png_size_t length)
{
using namespace pnglibNamespace;
InputStream* const in = (InputStream*) png_get_io_ptr (pngReadStruct);
in->read (data, (int) length);
static_cast<InputStream*> (png->io_ptr)->read (data, (int) length);
}
static void writeDataCallback (png_structp png, png_bytep data, png_size_t length)
{
static_cast<OutputStream*> (png->io_ptr)->write (data, (int) length);
}
struct PNGErrorStruct {};
@ -210956,17 +210969,6 @@ namespace PNGHelpers
{
throw PNGErrorStruct();
}
static void writeDataCallback (png_structp png_ptr, png_bytep data, png_size_t length)
{
OutputStream* const out = (OutputStream*) png_ptr->io_ptr;
const bool ok = out->write (data, (int) length);
(void) ok;
jassert (ok);
}
}
Image* juce_loadPNGImageFromStream (InputStream& in)
@ -240405,10 +240407,11 @@ END_JUCE_NAMESPACE
#define JuceUIView MakeObjCClassName(JuceUIView)
@interface JuceUIView : UIView
@interface JuceUIView : UIView <UITextFieldDelegate>
{
@public
UIViewComponentPeer* owner;
UITextField *hiddenTextField;
}
- (JuceUIView*) initWithOwner: (UIViewComponentPeer*) owner withFrame: (CGRect) frame;
@ -240427,6 +240430,9 @@ END_JUCE_NAMESPACE
- (void) asyncRepaint: (id) rect;
- (BOOL) textField: (UITextField*) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString*) string;
- (BOOL) textFieldShouldClear: (UITextField*) textField;
- (BOOL) textFieldShouldReturn: (UITextField*) textField;
@end
#define JuceUIWindow MakeObjCClassName(JuceUIWindow)
@ -240444,7 +240450,8 @@ END_JUCE_NAMESPACE
BEGIN_JUCE_NAMESPACE
class UIViewComponentPeer : public ComponentPeer
class UIViewComponentPeer : public ComponentPeer,
public FocusChangeListener
{
public:
UIViewComponentPeer (Component* const component,
@ -240490,6 +240497,12 @@ public:
void grabFocus();
void textInputRequired (const Point<int>& position);
virtual BOOL textFieldReplaceCharacters (const Range<int>& range, const String& text);
virtual BOOL textFieldShouldClear();
virtual BOOL textFieldShouldReturn();
void updateHiddenTextContent (TextInputTarget* target);
void globalFocusChanged (Component*);
void handleTouches (UIEvent* e, bool isDown, bool isUp, bool isCancel);
void repaint (int x, int y, int w, int h);
@ -240521,11 +240534,18 @@ END_JUCE_NAMESPACE
[super initWithFrame: frame];
owner = owner_;
hiddenTextField = [[UITextField alloc] initWithFrame: CGRectMake (0, 0, 0, 0)];
[self addSubview: hiddenTextField];
hiddenTextField.delegate = self;
return self;
}
- (void) dealloc
{
[hiddenTextField removeFromSuperview];
[hiddenTextField release];
[super dealloc];
}
@ -240607,6 +240627,22 @@ JUCE_NAMESPACE::Point<int> juce_lastMousePos;
[self setNeedsDisplayInRect: *r];
}
- (BOOL) textField: (UITextField*) textField shouldChangeCharactersInRange: (NSRange) range replacementString: (NSString*) text
{
return owner->textFieldReplaceCharacters (Range<int> (range.location, range.location + range.length),
nsStringToJuce (text));
}
- (BOOL) textFieldShouldClear: (UITextField*) textField
{
return owner->textFieldShouldClear();
}
- (BOOL) textFieldShouldReturn: (UITextField*) textField
{
return owner->textFieldShouldReturn();
}
@end
@implementation JuceUIWindow
@ -240679,10 +240715,14 @@ UIViewComponentPeer::UIViewComponentPeer (Component* const component,
}
setTitle (component->getName());
Desktop::getInstance().addFocusChangeListener (this);
}
UIViewComponentPeer::~UIViewComponentPeer()
{
Desktop::getInstance().removeFocusChangeListener (this);
view->owner = 0;
[view removeFromSuperview];
[view release];
@ -241029,6 +241069,77 @@ void UIViewComponentPeer::textInputRequired (const Point<int>&)
{
}
void UIViewComponentPeer::updateHiddenTextContent (TextInputTarget* target)
{
view->hiddenTextField.text = juceStringToNS (target->getTextInRange (Range<int> (0, target->getHighlightedRegion().getStart())));
}
BOOL UIViewComponentPeer::textFieldReplaceCharacters (const Range<int>& range, const String& text)
{
TextInputTarget* const target = findCurrentTextInputTarget();
if (target != 0)
{
const Range<int> currentSelection (target->getHighlightedRegion());
if (range.getLength() == 1 && text.isEmpty()) // (detect backspace)
if (currentSelection.isEmpty())
target->setHighlightedRegion (currentSelection.withStart (currentSelection.getStart() - 1));
target->insertTextAtCaret (text);
updateHiddenTextContent (target);
}
return NO;
}
BOOL UIViewComponentPeer::textFieldShouldClear()
{
TextInputTarget* const target = findCurrentTextInputTarget();
if (target != 0)
{
target->setHighlightedRegion (Range<int> (0, std::numeric_limits<int>::max()));
target->insertTextAtCaret (String::empty);
updateHiddenTextContent (target);
}
return YES;
}
BOOL UIViewComponentPeer::textFieldShouldReturn()
{
TextInputTarget* const target = findCurrentTextInputTarget();
if (target != 0)
{
target->insertTextAtCaret (T("\n"));
updateHiddenTextContent (target);
}
return YES;
}
void UIViewComponentPeer::globalFocusChanged (Component*)
{
TextInputTarget* const target = findCurrentTextInputTarget();
if (target != 0)
{
Component* comp = dynamic_cast<Component*> (target);
Point<int> pos (comp->relativePositionToOtherComponent (component, Point<int>()));
view->hiddenTextField.frame = CGRectMake (pos.getX(), pos.getY(), 0, 0);
updateHiddenTextContent (target);
[view->hiddenTextField becomeFirstResponder];
}
else
{
[view->hiddenTextField resignFirstResponder];
}
}
void UIViewComponentPeer::drawRect (CGRect r)
{
if (r.size.width < 1.0f || r.size.height < 1.0f)