Add right-click to ui::Entry to show edit popup menu (cut/copy/paste)

This commit is contained in:
David Capello 2014-08-31 22:51:17 -03:00
parent 3704cb0ae4
commit 7d89167e00
8 changed files with 123 additions and 79 deletions

View File

@ -144,7 +144,7 @@ protected:
menu->addChild(item);
const gfx::Rect& bounds = m_selectFile.getBounds();
menu->showPopup(bounds.x, bounds.y+bounds.h);
menu->showPopup(gfx::Point(bounds.x, bounds.y+bounds.h));
}
void onUseCurrentSprite()

View File

@ -292,7 +292,7 @@ void MainWindow::clickTab(Tabs* tabs, TabView* tabView, ui::MouseButtons buttons
if (buttons & kButtonRight) {
Menu* popup_menu = AppMenus::instance()->getDocumentTabPopupMenu();
if (popup_menu != NULL) {
popup_menu->showPopup(jmouse_x(0), jmouse_y(0));
popup_menu->showPopup(ui::get_mouse_position());
}
}
// Middle-button: close the sprite

View File

@ -88,9 +88,9 @@ void Notifications::onClick(ui::Event& ev)
invalidate();
gfx::Rect bounds = getBounds();
m_popup.showPopup(
m_popup.showPopup(gfx::Point(
bounds.x - m_popup.getPreferredSize().w,
bounds.y + bounds.h);
bounds.y + bounds.h));
}
} // namespace app

View File

@ -670,10 +670,8 @@ bool Timeline::onProcessMessage(Message* msg)
if (mouseMsg->right()) {
if (m_clk_frame == m_hot_frame) {
Menu* popup_menu = AppMenus::instance()->getFramePopupMenu();
if (popup_menu != NULL) {
gfx::Point mousePos = mouseMsg->position();
popup_menu->showPopup(mousePos.x, mousePos.y);
}
if (popup_menu)
popup_menu->showPopup(mouseMsg->position());
}
}
break;
@ -683,10 +681,8 @@ bool Timeline::onProcessMessage(Message* msg)
if (mouseMsg->right()) {
if (m_clk_layer == m_hot_layer) {
Menu* popup_menu = AppMenus::instance()->getLayerPopupMenu();
if (popup_menu != NULL) {
gfx::Point mousePos = mouseMsg->position();
popup_menu->showPopup(mousePos.x, mousePos.y);
}
if (popup_menu != NULL)
popup_menu->showPopup(mouseMsg->position());
}
}
break;
@ -721,10 +717,8 @@ bool Timeline::onProcessMessage(Message* msg)
AppMenus::instance()->getCelMovementPopupMenu():
AppMenus::instance()->getCelPopupMenu();
if (popup_menu != NULL) {
gfx::Point mousePos = mouseMsg->position();
popup_menu->showPopup(mousePos.x, mousePos.y);
}
if (popup_menu)
popup_menu->showPopup(mouseMsg->position());
}
break;
}

View File

@ -1,5 +1,5 @@
// Aseprite UI Library
// Copyright (C) 2001-2013 David Capello
// Copyright (C) 2001-2014 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -14,21 +14,33 @@
#include "she/font.h"
#include "ui/clipboard.h"
#include "ui/manager.h"
#include "ui/menu.h"
#include "ui/message.h"
#include "ui/preferred_size_event.h"
#include "ui/system.h"
#include "ui/theme.h"
#include "ui/widget.h"
#include <cctype>
#include <cstdarg>
#include <cstdio>
#include <cctype>
#include <functional>
namespace ui {
Entry::Entry(size_t maxsize, const char *format, ...)
: Widget(kEntryWidget)
, m_timer(500, this)
, m_maxsize(maxsize)
, m_caret(0)
, m_scroll(0)
, m_select(0)
, m_hidden(false)
, m_state(false)
, m_readonly(false)
, m_password(false)
, m_recent_focused(false)
, m_lock_selection(false)
{
char buf[4096];
@ -44,18 +56,8 @@ Entry::Entry(size_t maxsize, const char *format, ...)
buf[0] = 0;
}
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;
/* TODO support for text alignment and multi-line */
/* widget->align = JI_LEFT | JI_MIDDLE; */
// TODO support for text alignment and multi-line
// widget->align = JI_LEFT | JI_MIDDLE;
setText(buf);
setFocusStop(true);
@ -194,8 +196,13 @@ bool Entry::onProcessMessage(Message* msg)
m_state = true;
invalidate();
selectText(0, -1);
if (m_lock_selection) {
m_lock_selection = false;
}
else {
selectAllText();
m_recent_focused = true;
}
break;
case kFocusLeaveMessage:
@ -203,14 +210,16 @@ bool Entry::onProcessMessage(Message* msg)
m_timer.stop();
if (!m_lock_selection)
deselectText();
m_recent_focused = false;
break;
case kKeyDownMessage:
if (hasFocus() && !isReadOnly()) {
// Command to execute
EntryCmd::Type cmd = EntryCmd::NoOp;
EntryCmd cmd = EntryCmd::NoOp;
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
KeyScancode scancode = keymsg->scancode();
@ -333,10 +342,12 @@ bool Entry::onProcessMessage(Message* msg)
}
}
// Move caret
if (move) {
c = getCaretFromMouse(static_cast<MouseMessage*>(msg));
if (static_cast<MouseMessage*>(msg)->left() ||
(move && !isPosInSelection(c))) {
// Move caret
if (move) {
if (m_caret != c) {
m_caret = c;
is_dirty = true;
@ -351,6 +362,7 @@ bool Entry::onProcessMessage(Message* msg)
}
else if (msg->type() == kMouseDownMessage)
m_select = m_caret;
}
// Show the caret
if (is_dirty) {
@ -363,8 +375,18 @@ bool Entry::onProcessMessage(Message* msg)
break;
case kMouseUpMessage:
if (hasCapture())
if (hasCapture()) {
releaseMouse();
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
if (mouseMsg->right()) {
// This flag is disabled in kFocusEnterMessage message handler.
m_lock_selection = true;
showEditPopupMenu(mouseMsg->position());
requestFocus();
}
}
return true;
case kDoubleClickMessage:
@ -376,7 +398,7 @@ bool Entry::onProcessMessage(Message* msg)
case kMouseEnterMessage:
case kMouseLeaveMessage:
/* TODO theme stuff */
// TODO theme stuff
if (isEnabled())
invalidate();
break;
@ -461,7 +483,7 @@ int Entry::getCaretFromMouse(MouseMessage* mousemsg)
return caret;
}
void Entry::executeCmd(EntryCmd::Type cmd, int unicodeChar, bool shift_pressed)
void Entry::executeCmd(EntryCmd cmd, int unicodeChar, bool shift_pressed)
{
std::wstring text = base::from_utf8(getText());
int c, selbeg, selend;
@ -693,4 +715,30 @@ int Entry::getAvailableTextLength()
return getClientChildrenBounds().w / getFont()->charWidth('w');
}
bool Entry::isPosInSelection(int pos)
{
return (pos >= MIN(m_caret, m_select) && pos <= MAX(m_caret, m_select));
}
void Entry::showEditPopupMenu(const gfx::Point& pt)
{
Menu menu;
MenuItem cut("Cut");
MenuItem copy("Copy");
MenuItem paste("Paste");
menu.addChild(&cut);
menu.addChild(&copy);
menu.addChild(&paste);
cut.Click.connect(std::bind(&Entry::executeCmd, this, EntryCmd::Cut, 0, false));
copy.Click.connect(std::bind(&Entry::executeCmd, this, EntryCmd::Copy, 0, false));
paste.Click.connect(std::bind(&Entry::executeCmd, this, EntryCmd::Paste, 0, false));
if (isReadOnly()) {
cut.setEnabled(false);
paste.setEnabled(false);
}
menu.showPopup(pt);
}
} // namespace ui

View File

@ -56,8 +56,7 @@ namespace ui {
virtual void onEntryChange();
private:
struct EntryCmd {
enum Type {
enum class EntryCmd {
NoOp,
InsertChar,
ForwardChar,
@ -72,24 +71,26 @@ namespace ui {
Copy,
Paste,
};
};
int getCaretFromMouse(MouseMessage* mousemsg);
void executeCmd(EntryCmd::Type cmd, int ascii, bool shift_pressed);
void executeCmd(EntryCmd cmd, int ascii, bool shift_pressed);
void forwardWord();
void backwardWord();
int getAvailableTextLength();
bool isPosInSelection(int pos);
void showEditPopupMenu(const gfx::Point& pt);
Timer m_timer;
size_t m_maxsize;
int m_caret;
int m_scroll;
int m_select;
Timer m_timer;
bool m_hidden : 1;
bool m_state : 1; // show or not the text caret
bool m_readonly : 1;
bool m_password : 1;
bool m_recent_focused : 1;
bool m_hidden;
bool m_state; // show or not the text caret
bool m_readonly;
bool m_password;
bool m_recent_focused;
bool m_lock_selection;
std::string m_suffix;
};

View File

@ -266,7 +266,7 @@ bool MenuItem::hasSubmenu() const
return (m_submenu && !m_submenu->getChildren().empty());
}
void Menu::showPopup(int x, int y)
void Menu::showPopup(const gfx::Point& pos)
{
// New window and new menu-box
Window* window = new Window(Window::WithoutTitleBar);
@ -285,8 +285,9 @@ void Menu::showPopup(int x, int y)
window->remapWindow();
// Menubox position
window->positionWindow(MID(0, x, ui::display_w()-window->getBounds().w),
MID(0, y, ui::display_h()-window->getBounds().h));
window->positionWindow(
MID(0, pos.x, ui::display_w() - window->getBounds().w),
MID(0, pos.y, ui::display_h() - window->getBounds().h));
// Set the focus to the new menubox
Manager::getDefault()->setFocus(menubox);

View File

@ -26,7 +26,7 @@ namespace ui {
Menu();
~Menu();
void showPopup(int x, int y);
void showPopup(const gfx::Point& pos);
// Returns the MenuItem that has as submenu this menu.
MenuItem* getOwnerMenuItem() {