2012-01-06 12:12:57 +08:00
|
|
|
// ASEPRITE gui library
|
2013-01-27 23:13:13 +08:00
|
|
|
// Copyright (C) 2001-2013 David Capello
|
2010-09-28 06:18:17 +08:00
|
|
|
//
|
2012-09-24 10:24:07 +08:00
|
|
|
// This source file is distributed under a BSD-like license, please
|
2010-09-28 06:18:17 +08:00
|
|
|
// read LICENSE.txt for more information.
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2009-07-13 04:29:16 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2013-03-31 00:11:49 +08:00
|
|
|
#include "ui/entry.h"
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/clipboard.h"
|
|
|
|
#include "ui/font.h"
|
|
|
|
#include "ui/manager.h"
|
|
|
|
#include "ui/message.h"
|
|
|
|
#include "ui/preferred_size_event.h"
|
|
|
|
#include "ui/rect.h"
|
|
|
|
#include "ui/system.h"
|
|
|
|
#include "ui/theme.h"
|
|
|
|
#include "ui/widget.h"
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-03-31 00:11:49 +08:00
|
|
|
#include <allegro.h>
|
|
|
|
#include <allegro/internal/aintern.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2008-01-07 23:10:17 +08:00
|
|
|
#define CHARACTER_LENGTH(f, c) ((f)->vtable->char_length((f), (c)))
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
namespace ui {
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
Entry::Entry(size_t maxsize, const char *format, ...)
|
2013-04-04 09:07:24 +08:00
|
|
|
: Widget(kEntryWidget)
|
2012-07-06 12:06:00 +08:00
|
|
|
, m_timer(500, this)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
|
2009-05-31 05:22:52 +08:00
|
|
|
// formatted string
|
2007-09-19 07:57:02 +08:00
|
|
|
if (format) {
|
|
|
|
va_list ap;
|
2008-01-04 07:22:04 +08:00
|
|
|
va_start(ap, format);
|
|
|
|
vsprintf(buf, format, ap);
|
|
|
|
va_end(ap);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2009-05-31 05:22:52 +08:00
|
|
|
// empty string
|
2007-09-19 07:57:02 +08:00
|
|
|
else {
|
2008-01-04 07:22:04 +08:00
|
|
|
ustrcpy(buf, empty_string);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_maxsize = maxsize;
|
|
|
|
m_caret = 0;
|
|
|
|
m_scroll = 0;
|
|
|
|
m_select = 0;
|
|
|
|
m_hidden = false;
|
|
|
|
m_state = false;
|
|
|
|
m_password = false;
|
|
|
|
m_readonly = false;
|
|
|
|
m_recent_focused = false;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2007-12-05 05:50:31 +08:00
|
|
|
/* TODO support for text alignment and multi-line */
|
2007-09-19 07:57:02 +08:00
|
|
|
/* widget->align = JI_LEFT | JI_MIDDLE; */
|
2010-12-09 01:28:13 +08:00
|
|
|
setText(buf);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-04-06 06:00:19 +08:00
|
|
|
this->setFocusStop(true);
|
2011-02-15 20:00:29 +08:00
|
|
|
initTheme();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
Entry::~Entry()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
bool Entry::isReadOnly() const
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
return m_readonly;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
bool Entry::isPassword() const
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
return m_password;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::setReadOnly(bool state)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
m_readonly = state;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::setPassword(bool state)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
m_password = state;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::showCaret()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
m_hidden = false;
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2010-12-09 01:28:13 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::hideCaret()
|
|
|
|
{
|
|
|
|
m_hidden = true;
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::setCaretPos(int pos)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
const char *text = this->getText();
|
2007-09-19 07:57:02 +08:00
|
|
|
int x, c;
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_caret = pos;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
|
|
|
/* backward scroll */
|
2010-12-09 01:28:13 +08:00
|
|
|
if (m_caret < m_scroll)
|
|
|
|
m_scroll = m_caret;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
|
|
|
/* forward scroll */
|
2010-12-09 01:28:13 +08:00
|
|
|
m_scroll--;
|
2007-09-19 07:57:02 +08:00
|
|
|
do {
|
2010-12-09 01:28:13 +08:00
|
|
|
x = this->rc->x1 + this->border_width.l;
|
|
|
|
for (c=++m_scroll; ; c++) {
|
|
|
|
x += CHARACTER_LENGTH(this->getFont(),
|
2012-01-06 06:45:03 +08:00
|
|
|
(c < ustrlen(text))? ugetat(text, c): ' ');
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
if (x >= this->rc->x2-this->border_width.r)
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-12-09 01:28:13 +08:00
|
|
|
} while (m_caret >= c);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-04-08 00:12:01 +08:00
|
|
|
m_timer.start();
|
2010-12-09 01:28:13 +08:00
|
|
|
m_state = true;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::selectText(int from, int to)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
int end = ustrlen(this->getText());
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_select = from;
|
|
|
|
setCaretPos(from); // to move scroll
|
|
|
|
setCaretPos((to >= 0)? to: end+to+1);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::deselectText()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
m_select = -1;
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2013-03-30 03:20:32 +08:00
|
|
|
void Entry::setSuffix(const std::string& suffix)
|
|
|
|
{
|
|
|
|
m_suffix = suffix;
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::getEntryThemeInfo(int* scroll, int* caret, int* state,
|
2012-01-06 06:45:03 +08:00
|
|
|
int* selbeg, int* selend)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
if (scroll) *scroll = m_scroll;
|
|
|
|
if (caret) *caret = m_caret;
|
|
|
|
if (state) *state = !m_hidden && m_state;
|
|
|
|
|
|
|
|
if ((m_select >= 0) &&
|
|
|
|
(m_caret != m_select)) {
|
|
|
|
*selbeg = MIN(m_caret, m_select);
|
|
|
|
*selend = MAX(m_caret, m_select)-1;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
*selbeg = -1;
|
|
|
|
*selend = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-03 00:14:07 +08:00
|
|
|
bool Entry::onProcessMessage(Message* msg)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
switch (msg->type) {
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kTimerMessage:
|
2012-04-08 00:12:01 +08:00
|
|
|
if (this->hasFocus() && msg->timer.timer == &m_timer) {
|
2012-01-06 06:45:03 +08:00
|
|
|
// Blinking caret
|
|
|
|
m_state = m_state ? false: true;
|
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kFocusEnterMessage:
|
2012-04-08 00:12:01 +08:00
|
|
|
m_timer.start();
|
2008-01-04 07:22:04 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_state = true;
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
selectText(0, -1);
|
|
|
|
m_recent_focused = true;
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kFocusLeaveMessage:
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-04-08 00:12:01 +08:00
|
|
|
m_timer.stop();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
deselectText();
|
|
|
|
m_recent_focused = false;
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kKeyDownMessage:
|
2010-12-09 01:28:13 +08:00
|
|
|
if (this->hasFocus() && !isReadOnly()) {
|
2012-01-06 06:45:03 +08:00
|
|
|
// Command to execute
|
|
|
|
EntryCmd::Type cmd = EntryCmd::NoOp;
|
|
|
|
|
|
|
|
switch (msg->key.scancode) {
|
|
|
|
|
|
|
|
case KEY_LEFT:
|
|
|
|
if (msg->any.shifts & KB_CTRL_FLAG)
|
|
|
|
cmd = EntryCmd::BackwardWord;
|
|
|
|
else
|
|
|
|
cmd = EntryCmd::BackwardChar;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_RIGHT:
|
|
|
|
if (msg->any.shifts & KB_CTRL_FLAG)
|
|
|
|
cmd = EntryCmd::ForwardWord;
|
|
|
|
else
|
|
|
|
cmd = EntryCmd::ForwardChar;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_HOME:
|
|
|
|
cmd = EntryCmd::BeginningOfLine;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_END:
|
|
|
|
cmd = EntryCmd::EndOfLine;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_DEL:
|
|
|
|
if (msg->any.shifts & KB_SHIFT_FLAG)
|
|
|
|
cmd = EntryCmd::Cut;
|
|
|
|
else
|
|
|
|
cmd = EntryCmd::DeleteForward;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_INSERT:
|
|
|
|
if (msg->any.shifts & KB_SHIFT_FLAG)
|
|
|
|
cmd = EntryCmd::Paste;
|
|
|
|
else if (msg->any.shifts & KB_CTRL_FLAG)
|
|
|
|
cmd = EntryCmd::Copy;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case KEY_BACKSPACE:
|
|
|
|
cmd = EntryCmd::DeleteBackward;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (msg->key.ascii >= 32) {
|
2012-04-16 02:56:47 +08:00
|
|
|
// Ctrl and Alt must be unpressed to insert a character
|
|
|
|
// in the text-field.
|
|
|
|
if ((msg->any.shifts & (KB_CTRL_FLAG | KB_ALT_FLAG)) == 0) {
|
|
|
|
cmd = EntryCmd::InsertChar;
|
|
|
|
}
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// map common Windows shortcuts for Cut/Copy/Paste
|
|
|
|
if ((msg->any.shifts & (KB_CTRL_FLAG | KB_SHIFT_FLAG | KB_ALT_FLAG)) == KB_CTRL_FLAG) {
|
|
|
|
switch (msg->key.scancode) {
|
|
|
|
case KEY_X: cmd = EntryCmd::Cut; break;
|
|
|
|
case KEY_C: cmd = EntryCmd::Copy; break;
|
|
|
|
case KEY_V: cmd = EntryCmd::Paste; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd == EntryCmd::NoOp)
|
|
|
|
break;
|
|
|
|
|
|
|
|
executeCmd(cmd,
|
|
|
|
msg->key.ascii,
|
|
|
|
(msg->any.shifts & KB_SHIFT_FLAG) ? true: false);
|
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseDownMessage:
|
2010-12-09 01:28:13 +08:00
|
|
|
this->captureMouse();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseMoveMessage:
|
2010-12-09 01:28:13 +08:00
|
|
|
if (this->hasCapture()) {
|
2012-01-06 06:45:03 +08:00
|
|
|
const char *text = this->getText();
|
|
|
|
bool move, is_dirty;
|
|
|
|
int c, x;
|
|
|
|
|
|
|
|
move = true;
|
|
|
|
is_dirty = false;
|
|
|
|
|
|
|
|
/* backward scroll */
|
|
|
|
if (msg->mouse.x < this->rc->x1) {
|
|
|
|
if (m_scroll > 0) {
|
|
|
|
m_caret = --m_scroll;
|
|
|
|
move = false;
|
|
|
|
is_dirty = true;
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* forward scroll */
|
|
|
|
else if (msg->mouse.x >= this->rc->x2) {
|
|
|
|
if (m_scroll < ustrlen(text)) {
|
|
|
|
m_scroll++;
|
|
|
|
x = this->rc->x1 + this->border_width.l;
|
|
|
|
for (c=m_scroll; ; c++) {
|
|
|
|
x += CHARACTER_LENGTH(this->getFont(),
|
|
|
|
(c < ustrlen(text))? ugetat(text, c): ' ');
|
|
|
|
if (x > this->rc->x2-this->border_width.r) {
|
|
|
|
c--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (!ugetat (text, c))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m_caret = c;
|
|
|
|
move = false;
|
|
|
|
is_dirty = true;
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move caret
|
|
|
|
if (move) {
|
|
|
|
c = getCaretFromMouse(msg);
|
|
|
|
|
|
|
|
if (m_caret != c) {
|
|
|
|
m_caret = c;
|
|
|
|
is_dirty = true;
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Move selection
|
|
|
|
if (m_recent_focused) {
|
|
|
|
m_recent_focused = false;
|
|
|
|
m_select = m_caret;
|
|
|
|
}
|
2013-04-05 08:53:29 +08:00
|
|
|
else if (msg->type == kMouseDownMessage)
|
2012-01-06 06:45:03 +08:00
|
|
|
m_select = m_caret;
|
|
|
|
|
|
|
|
// Show the caret
|
|
|
|
if (is_dirty) {
|
2012-04-08 00:12:01 +08:00
|
|
|
m_timer.start();
|
2012-01-06 06:45:03 +08:00
|
|
|
m_state = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseUpMessage:
|
2010-12-09 01:28:13 +08:00
|
|
|
if (this->hasCapture())
|
2012-01-06 06:45:03 +08:00
|
|
|
this->releaseMouse();
|
2009-08-18 02:00:38 +08:00
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kDoubleClickMessage:
|
2010-12-09 01:28:13 +08:00
|
|
|
forwardWord();
|
|
|
|
m_select = m_caret;
|
|
|
|
backwardWord();
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2009-08-18 02:00:38 +08:00
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseEnterMessage:
|
|
|
|
case kMouseLeaveMessage:
|
2007-12-05 05:50:31 +08:00
|
|
|
/* TODO theme stuff */
|
2010-12-09 01:28:13 +08:00
|
|
|
if (this->isEnabled())
|
2012-01-06 06:45:03 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
return Widget::onProcessMessage(msg);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::onPreferredSize(PreferredSizeEvent& ev)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
int w =
|
|
|
|
+ border_width.l
|
|
|
|
+ ji_font_char_len(getFont(), 'w') * MIN(m_maxsize, 6)
|
|
|
|
+ 2 + border_width.r;
|
2009-05-31 05:22:52 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
w = MIN(w, JI_SCREEN_W/2);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
int h =
|
2010-12-09 01:28:13 +08:00
|
|
|
+ border_width.t
|
|
|
|
+ text_height(getFont())
|
|
|
|
+ border_width.b;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
ev.setPreferredSize(w, h);
|
|
|
|
}
|
|
|
|
|
2011-02-12 20:32:57 +08:00
|
|
|
void Entry::onPaint(PaintEvent& ev)
|
|
|
|
{
|
|
|
|
getTheme()->paintEntry(ev);
|
|
|
|
}
|
|
|
|
|
2013-03-30 11:35:25 +08:00
|
|
|
void Entry::onSetText()
|
|
|
|
{
|
|
|
|
Widget::onSetText();
|
|
|
|
|
|
|
|
if (m_caret >= 0 && (size_t)m_caret > getTextSize())
|
|
|
|
m_caret = (int)getTextSize();
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::onEntryChange()
|
|
|
|
{
|
|
|
|
EntryChange();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2011-04-03 00:14:07 +08:00
|
|
|
int Entry::getCaretFromMouse(Message* msg)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
int c, x, w, mx, caret = m_caret;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
|
|
|
mx = msg->mouse.x;
|
2010-12-09 01:28:13 +08:00
|
|
|
mx = MID(this->rc->x1+this->border_width.l,
|
2012-01-06 06:45:03 +08:00
|
|
|
mx,
|
|
|
|
this->rc->x2-this->border_width.r-1);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
x = this->rc->x1 + this->border_width.l;
|
|
|
|
for (c=m_scroll; ugetat(this->getText(), c); c++) {
|
|
|
|
w = CHARACTER_LENGTH(this->getFont(), ugetat(this->getText(), c));
|
|
|
|
if (x+w >= this->rc->x2-this->border_width.r)
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
if ((mx >= x) && (mx < x+w)) {
|
2010-12-09 01:28:13 +08:00
|
|
|
caret = c;
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
x += w;
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
if (!ugetat(this->getText(), c))
|
2007-09-19 07:57:02 +08:00
|
|
|
if ((mx >= x) &&
|
2012-01-06 06:45:03 +08:00
|
|
|
(mx <= this->rc->x2-this->border_width.r-1))
|
2010-12-09 01:28:13 +08:00
|
|
|
caret = c;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
return caret;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::executeCmd(EntryCmd::Type cmd, int ascii, bool shift_pressed)
|
2009-08-10 05:24:32 +08:00
|
|
|
{
|
2010-12-09 01:28:13 +08:00
|
|
|
std::string text = this->getText();
|
2009-08-10 05:24:32 +08:00
|
|
|
int c, selbeg, selend;
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
getEntryThemeInfo(NULL, NULL, NULL, &selbeg, &selend);
|
2009-08-10 05:24:32 +08:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
|
2010-08-12 10:42:03 +08:00
|
|
|
case EntryCmd::NoOp:
|
|
|
|
break;
|
|
|
|
|
2009-08-10 05:24:32 +08:00
|
|
|
case EntryCmd::InsertChar:
|
|
|
|
// delete the entire selection
|
|
|
|
if (selbeg >= 0) {
|
2012-01-06 06:45:03 +08:00
|
|
|
text.erase(selbeg, selend-selbeg+1);
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
m_caret = selbeg;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// put the character
|
2013-03-30 11:35:25 +08:00
|
|
|
if (text.size() < m_maxsize) {
|
|
|
|
ASSERT((size_t)m_caret <= text.size());
|
2012-01-06 06:45:03 +08:00
|
|
|
text.insert(m_caret++, 1, ascii);
|
2013-03-30 11:35:25 +08:00
|
|
|
}
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::BackwardChar:
|
|
|
|
case EntryCmd::BackwardWord:
|
|
|
|
// selection
|
|
|
|
if (shift_pressed) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_select < 0)
|
|
|
|
m_select = m_caret;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
else
|
2012-01-06 06:45:03 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
|
|
|
|
// backward word
|
|
|
|
if (cmd == EntryCmd::BackwardWord) {
|
2012-01-06 06:45:03 +08:00
|
|
|
backwardWord();
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
// backward char
|
2010-12-09 01:28:13 +08:00
|
|
|
else if (m_caret > 0) {
|
2012-01-06 06:45:03 +08:00
|
|
|
m_caret--;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::ForwardChar:
|
|
|
|
case EntryCmd::ForwardWord:
|
|
|
|
// selection
|
|
|
|
if (shift_pressed) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_select < 0)
|
|
|
|
m_select = m_caret;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
else
|
2012-01-06 06:45:03 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
|
|
|
|
// forward word
|
|
|
|
if (cmd == EntryCmd::ForwardWord) {
|
2012-01-06 06:45:03 +08:00
|
|
|
forwardWord();
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
// forward char
|
2010-12-09 01:28:13 +08:00
|
|
|
else if (m_caret < (int)text.size()) {
|
2012-01-06 06:45:03 +08:00
|
|
|
m_caret++;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::BeginningOfLine:
|
|
|
|
// selection
|
|
|
|
if (shift_pressed) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_select < 0)
|
|
|
|
m_select = m_caret;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
else
|
2012-01-06 06:45:03 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_caret = 0;
|
2009-08-10 05:24:32 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::EndOfLine:
|
|
|
|
// selection
|
|
|
|
if (shift_pressed) {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_select < 0)
|
|
|
|
m_select = m_caret;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
else
|
2012-01-06 06:45:03 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_caret = text.size();
|
2009-08-10 05:24:32 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::DeleteForward:
|
|
|
|
case EntryCmd::Cut:
|
|
|
|
// delete the entire selection
|
|
|
|
if (selbeg >= 0) {
|
2012-01-06 06:45:03 +08:00
|
|
|
// *cut* text!
|
|
|
|
if (cmd == EntryCmd::Cut) {
|
|
|
|
base::string buf = text.substr(selbeg, selend - selbeg + 1);
|
2012-06-18 09:02:54 +08:00
|
|
|
clipboard::set_text(buf.c_str());
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
// remove text
|
|
|
|
text.erase(selbeg, selend-selbeg+1);
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
m_caret = selbeg;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
// delete the next character
|
|
|
|
else {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_caret < (int)text.size())
|
|
|
|
text.erase(m_caret, 1);
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::Paste: {
|
|
|
|
const char *clipboard;
|
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
if ((clipboard = clipboard::get_text())) {
|
2012-01-06 06:45:03 +08:00
|
|
|
// delete the entire selection
|
|
|
|
if (selbeg >= 0) {
|
|
|
|
text.erase(selbeg, selend-selbeg+1);
|
|
|
|
|
|
|
|
m_caret = selbeg;
|
|
|
|
m_select = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// paste text
|
|
|
|
for (c=0; c<ustrlen(clipboard); c++)
|
|
|
|
if (text.size() < m_maxsize)
|
|
|
|
text.insert(m_caret+c, 1, ugetat(clipboard, c));
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
|
|
|
|
setCaretPos(m_caret+c);
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case EntryCmd::Copy:
|
|
|
|
if (selbeg >= 0) {
|
2012-01-06 06:45:03 +08:00
|
|
|
base::string buf = text.substr(selbeg, selend - selbeg + 1);
|
2012-06-18 09:02:54 +08:00
|
|
|
clipboard::set_text(buf.c_str());
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EntryCmd::DeleteBackward:
|
|
|
|
// delete the entire selection
|
|
|
|
if (selbeg >= 0) {
|
2012-01-06 06:45:03 +08:00
|
|
|
text.erase(selbeg, selend-selbeg+1);
|
2009-08-10 05:24:32 +08:00
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
m_caret = selbeg;
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
// delete the previous character
|
|
|
|
else {
|
2012-01-06 06:45:03 +08:00
|
|
|
if (m_caret > 0)
|
|
|
|
text.erase(--m_caret, 1);
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
m_select = -1;
|
2009-08-10 05:24:32 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
if (text != this->getText()) {
|
|
|
|
this->setText(text.c_str());
|
|
|
|
onEntryChange();
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
setCaretPos(m_caret);
|
2011-01-22 06:45:04 +08:00
|
|
|
invalidate();
|
2009-08-10 05:24:32 +08:00
|
|
|
}
|
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
#define IS_WORD_CHAR(ch) \
|
|
|
|
(!((!ch) || (uisspace(ch)) || \
|
2007-09-19 07:57:02 +08:00
|
|
|
((ch) == '/') || ((ch) == OTHER_PATH_SEPARATOR)))
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::forwardWord()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
int ch;
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
for (; m_caret<ustrlen(this->getText()); m_caret++) {
|
|
|
|
ch = ugetat(this->getText(), m_caret);
|
2007-09-19 07:57:02 +08:00
|
|
|
if (IS_WORD_CHAR (ch))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
for (; m_caret<ustrlen(this->getText()); m_caret++) {
|
|
|
|
ch = ugetat(this->getText(), m_caret);
|
2008-01-04 07:22:04 +08:00
|
|
|
if (!IS_WORD_CHAR(ch)) {
|
2010-12-09 01:28:13 +08:00
|
|
|
m_caret++;
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
void Entry::backwardWord()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
|
|
|
int ch;
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
for (m_caret--; m_caret >= 0; m_caret--) {
|
|
|
|
ch = ugetat(this->getText(), m_caret);
|
2008-01-04 07:22:04 +08:00
|
|
|
if (IS_WORD_CHAR(ch))
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
for (; m_caret >= 0; m_caret--) {
|
|
|
|
ch = ugetat(this->getText(), m_caret);
|
2008-01-04 07:22:04 +08:00
|
|
|
if (!IS_WORD_CHAR(ch)) {
|
2010-12-09 01:28:13 +08:00
|
|
|
m_caret++;
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-09 01:28:13 +08:00
|
|
|
if (m_caret < 0)
|
|
|
|
m_caret = 0;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2012-06-18 09:02:54 +08:00
|
|
|
|
|
|
|
} // namespace ui
|