mirror of https://github.com/aseprite/aseprite.git
Add search field in keyboard shortcuts dialog (fix #849)
Changes: * Added "icon_search" part in the skin * Added app::SearchEntry widget * Fixed Separator widget to handle a custom background color, because now we use Separators inside a ListBox too * Added Entry::(on)getEntryTextBounds() to specify a customized area to show text (as SearchEntry needs space for search and close icons)
This commit is contained in:
parent
d5d1ac0d47
commit
771a7ba467
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -407,7 +407,8 @@
|
||||||
<part id="horizontal_symmetry" x="160" y="240" w="13" h="13" />
|
<part id="horizontal_symmetry" x="160" y="240" w="13" h="13" />
|
||||||
<part id="vertical_symmetry" x="176" y="240" w="13" h="13" />
|
<part id="vertical_symmetry" x="176" y="240" w="13" h="13" />
|
||||||
<part id="icon_arrow_down" x="144" y="256" w="7" h="4" />
|
<part id="icon_arrow_down" x="144" y="256" w="7" h="4" />
|
||||||
<part id="icon_close" x="153" y="256" w="7" h="7" />
|
<part id="icon_close" x="152" y="256" w="7" h="7" />
|
||||||
|
<part id="icon_search" x="160" y="256" w="8" h="8" />
|
||||||
</parts>
|
</parts>
|
||||||
|
|
||||||
<stylesheet>
|
<stylesheet>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<vbox>
|
<vbox>
|
||||||
<hbox expansive="true">
|
<hbox expansive="true">
|
||||||
<vbox>
|
<vbox>
|
||||||
|
<search id="search" magnet="true" />
|
||||||
<view width="80" expansive="true">
|
<view width="80" expansive="true">
|
||||||
<listbox id="section" expansive="true" />
|
<listbox id="section" expansive="true" />
|
||||||
</view>
|
</view>
|
||||||
|
|
@ -14,6 +15,9 @@
|
||||||
<button text="&Reset" id="reset_button" />
|
<button text="&Reset" id="reset_button" />
|
||||||
</vbox>
|
</vbox>
|
||||||
<vbox expansive="true">
|
<vbox expansive="true">
|
||||||
|
<view id="search_view" expansive="true">
|
||||||
|
<listbox id="search_list" />
|
||||||
|
</view>
|
||||||
<view id="menus_view" expansive="true">
|
<view id="menus_view" expansive="true">
|
||||||
<listbox id="menus" />
|
<listbox id="menus" />
|
||||||
</view>
|
</view>
|
||||||
|
|
|
||||||
|
|
@ -381,6 +381,7 @@ add_library(app-lib
|
||||||
ui/preview_editor.cpp
|
ui/preview_editor.cpp
|
||||||
ui/recent_listbox.cpp
|
ui/recent_listbox.cpp
|
||||||
ui/resources_listbox.cpp
|
ui/resources_listbox.cpp
|
||||||
|
ui/search_entry.cpp
|
||||||
ui/select_accelerator.cpp
|
ui/select_accelerator.cpp
|
||||||
ui/skin/button_icon_impl.cpp
|
ui/skin/button_icon_impl.cpp
|
||||||
ui/skin/skin_part.cpp
|
ui/skin/skin_part.cpp
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,21 @@
|
||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
#include "app/ui/app_menuitem.h"
|
#include "app/ui/app_menuitem.h"
|
||||||
#include "app/ui/keyboard_shortcuts.h"
|
#include "app/ui/keyboard_shortcuts.h"
|
||||||
|
#include "app/ui/search_entry.h"
|
||||||
#include "app/ui/select_accelerator.h"
|
#include "app/ui/select_accelerator.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "base/bind.h"
|
#include "base/bind.h"
|
||||||
#include "base/fs.h"
|
#include "base/fs.h"
|
||||||
#include "base/path.h"
|
#include "base/path.h"
|
||||||
|
#include "base/scoped_value.h"
|
||||||
|
#include "base/split_string.h"
|
||||||
|
#include "base/string.h"
|
||||||
#include "ui/graphics.h"
|
#include "ui/graphics.h"
|
||||||
#include "ui/listitem.h"
|
#include "ui/listitem.h"
|
||||||
#include "ui/paint_event.h"
|
#include "ui/paint_event.h"
|
||||||
#include "ui/preferred_size_event.h"
|
#include "ui/preferred_size_event.h"
|
||||||
#include "ui/resize_event.h"
|
#include "ui/resize_event.h"
|
||||||
|
#include "ui/separator.h"
|
||||||
|
|
||||||
#include "keyboard_shortcuts.xml.h"
|
#include "keyboard_shortcuts.xml.h"
|
||||||
|
|
||||||
|
|
@ -55,6 +60,8 @@ public:
|
||||||
setBorder(border);
|
setBorder(border);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Key* key() { return m_key; }
|
||||||
|
|
||||||
void restoreKeys() {
|
void restoreKeys() {
|
||||||
if (m_key && m_keyOrig)
|
if (m_key && m_keyOrig)
|
||||||
*m_key = *m_keyOrig;
|
*m_key = *m_keyOrig;
|
||||||
|
|
@ -280,7 +287,7 @@ private:
|
||||||
|
|
||||||
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts {
|
||||||
public:
|
public:
|
||||||
KeyboardShortcutsWindow() {
|
KeyboardShortcutsWindow() : m_searchChange(false) {
|
||||||
setAutoRemap(false);
|
setAutoRemap(false);
|
||||||
|
|
||||||
section()->addChild(new ListItem("Menus"));
|
section()->addChild(new ListItem("Menus"));
|
||||||
|
|
@ -288,6 +295,7 @@ public:
|
||||||
section()->addChild(new ListItem("Tools"));
|
section()->addChild(new ListItem("Tools"));
|
||||||
section()->addChild(new ListItem("Action Modifiers"));
|
section()->addChild(new ListItem("Action Modifiers"));
|
||||||
|
|
||||||
|
search()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSearchChange, this));
|
||||||
section()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this));
|
section()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this));
|
||||||
importButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onImport, this));
|
importButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onImport, this));
|
||||||
exportButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onExport, this));
|
exportButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onExport, this));
|
||||||
|
|
@ -304,6 +312,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void deleteAllKeyItems() {
|
void deleteAllKeyItems() {
|
||||||
|
while (searchList()->getLastChild())
|
||||||
|
searchList()->removeChild(searchList()->getLastChild());
|
||||||
while (menus()->getLastChild())
|
while (menus()->getLastChild())
|
||||||
menus()->removeChild(menus()->getLastChild());
|
menus()->removeChild(menus()->getLastChild());
|
||||||
while (commands()->getLastChild())
|
while (commands()->getLastChild())
|
||||||
|
|
@ -375,12 +385,78 @@ private:
|
||||||
this->actions()->sortItems();
|
this->actions()->sortItems();
|
||||||
|
|
||||||
section()->selectIndex(0);
|
section()->selectIndex(0);
|
||||||
onSectionChange();
|
updateViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillSearchList(const std::string& search) {
|
||||||
|
while (searchList()->getLastChild())
|
||||||
|
searchList()->removeChild(searchList()->getLastChild());
|
||||||
|
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
base::split_string(base::string_to_lower(search), parts, " ");
|
||||||
|
|
||||||
|
ListBox* listBoxes[] = { commands(), tools(), actions() };
|
||||||
|
int sectionIdx = 1; // index 0 is menus, index 1 is commands
|
||||||
|
for (auto listBox : listBoxes) {
|
||||||
|
Separator* group = nullptr;
|
||||||
|
|
||||||
|
for (auto item : listBox->getChildren()) {
|
||||||
|
if (KeyItem* keyItem = dynamic_cast<KeyItem*>(item)) {
|
||||||
|
std::string itemText =
|
||||||
|
base::string_to_lower(keyItem->getText());
|
||||||
|
int matches = 0;
|
||||||
|
|
||||||
|
for (const auto& part : parts) {
|
||||||
|
if (itemText.find(part) != std::string::npos)
|
||||||
|
++matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches == int(parts.size())) {
|
||||||
|
if (!group) {
|
||||||
|
group = new Separator(
|
||||||
|
section()->getChildren()[sectionIdx]->getText(), HORIZONTAL);
|
||||||
|
group->setBgColor(SkinTheme::instance()->colors.background());
|
||||||
|
|
||||||
|
searchList()->addChild(group);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyItem* copyItem =
|
||||||
|
new KeyItem(keyItem->getText(),
|
||||||
|
keyItem->key(), nullptr, 0);
|
||||||
|
searchList()->addChild(copyItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++sectionIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSearchChange() {
|
||||||
|
base::ScopedValue<bool> flag(m_searchChange, true, false);
|
||||||
|
std::string searchText = search()->getText();
|
||||||
|
|
||||||
|
if (searchText.empty())
|
||||||
|
section()->selectIndex(0);
|
||||||
|
else {
|
||||||
|
fillSearchList(searchText);
|
||||||
|
section()->selectChild(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateViews();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSectionChange() {
|
void onSectionChange() {
|
||||||
int section = this->section()->getSelectedIndex();
|
if (m_searchChange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
search()->setText("");
|
||||||
|
updateViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateViews() {
|
||||||
|
int section = this->section()->getSelectedIndex();
|
||||||
|
searchView()->setVisible(section < 0);
|
||||||
menusView()->setVisible(section == 0);
|
menusView()->setVisible(section == 0);
|
||||||
commandsView()->setVisible(section == 1);
|
commandsView()->setVisible(section == 1);
|
||||||
toolsView()->setVisible(section == 2);
|
toolsView()->setVisible(section == 2);
|
||||||
|
|
@ -438,6 +514,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<KeyItem*> m_allKeyItems;
|
std::vector<KeyItem*> m_allKeyItems;
|
||||||
|
bool m_searchChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
class KeyboardShortcutsCommand : public Command {
|
class KeyboardShortcutsCommand : public Command {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2015 David Capello
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2 as
|
||||||
|
// published by the Free Software Foundation.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/ui/search_entry.h"
|
||||||
|
|
||||||
|
#include "app/ui/skin/skin_theme.h"
|
||||||
|
#include "she/surface.h"
|
||||||
|
#include "ui/graphics.h"
|
||||||
|
#include "ui/message.h"
|
||||||
|
#include "ui/paint_event.h"
|
||||||
|
#include "ui/preferred_size_event.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace app::skin;
|
||||||
|
using namespace gfx;
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
SearchEntry::SearchEntry()
|
||||||
|
: Entry(256, "")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SearchEntry::onProcessMessage(ui::Message* msg)
|
||||||
|
{
|
||||||
|
switch (msg->type()) {
|
||||||
|
case kMouseDownMessage: {
|
||||||
|
Rect closeBounds = getCloseIconBounds();
|
||||||
|
Point mousePos = static_cast<MouseMessage*>(msg)->position()
|
||||||
|
- getBounds().getOrigin();
|
||||||
|
|
||||||
|
if (closeBounds.contains(mousePos)) {
|
||||||
|
setText("");
|
||||||
|
onChange();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Entry::onProcessMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchEntry::onPaint(ui::PaintEvent& ev)
|
||||||
|
{
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
|
||||||
|
theme->paintEntry(ev);
|
||||||
|
|
||||||
|
auto icon = theme->parts.iconSearch()->getBitmap(0);
|
||||||
|
Rect bounds = getClientBounds();
|
||||||
|
ev.getGraphics()->drawColoredRgbaSurface(
|
||||||
|
icon, theme->colors.text(),
|
||||||
|
bounds.x + border().left(),
|
||||||
|
bounds.y + bounds.h/2 - icon->height()/2);
|
||||||
|
|
||||||
|
if (!getText().empty()) {
|
||||||
|
icon = theme->parts.iconClose()->getBitmap(0);
|
||||||
|
ev.getGraphics()->drawColoredRgbaSurface(
|
||||||
|
icon, theme->colors.text(),
|
||||||
|
bounds.x + bounds.w - border().right() - childSpacing() - icon->width(),
|
||||||
|
bounds.y + bounds.h/2 - icon->height()/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SearchEntry::onPreferredSize(PreferredSizeEvent& ev)
|
||||||
|
{
|
||||||
|
Entry::onPreferredSize(ev);
|
||||||
|
Size sz = ev.getPreferredSize();
|
||||||
|
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
|
||||||
|
auto icon = theme->parts.iconSearch()->getBitmap(0);
|
||||||
|
sz.h = MAX(sz.h, icon->height()+border().height());
|
||||||
|
|
||||||
|
ev.setPreferredSize(sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect SearchEntry::onGetEntryTextBounds() const
|
||||||
|
{
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
|
||||||
|
Rect bounds = Entry::onGetEntryTextBounds();
|
||||||
|
auto icon1 = theme->parts.iconSearch()->getBitmap(0);
|
||||||
|
auto icon2 = theme->parts.iconClose()->getBitmap(0);
|
||||||
|
bounds.x += childSpacing() + icon1->width();
|
||||||
|
bounds.w -= 2*childSpacing() + icon1->width() + icon2->width();
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect SearchEntry::getCloseIconBounds() const
|
||||||
|
{
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
|
||||||
|
Rect bounds = getClientBounds();
|
||||||
|
auto icon = theme->parts.iconClose()->getBitmap(0);
|
||||||
|
bounds.x += bounds.w - border().right() - childSpacing() - icon->width();
|
||||||
|
bounds.y += bounds.h/2 - icon->height()/2;
|
||||||
|
bounds.w = icon->width();
|
||||||
|
bounds.h = icon->height();
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2001-2015 David Capello
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License version 2 as
|
||||||
|
// published by the Free Software Foundation.
|
||||||
|
|
||||||
|
#ifndef APP_UI_SEARCH_ENTRY_H_INCLUDED
|
||||||
|
#define APP_UI_SEARCH_ENTRY_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/entry.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class SearchEntry : public ui::Entry {
|
||||||
|
public:
|
||||||
|
SearchEntry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool onProcessMessage(ui::Message* msg) override;
|
||||||
|
void onPaint(ui::PaintEvent& ev) override;
|
||||||
|
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
|
||||||
|
gfx::Rect onGetEntryTextBounds() const override;
|
||||||
|
|
||||||
|
gfx::Rect getCloseIconBounds() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -568,6 +568,7 @@ void SkinTheme::initWidget(Widget* widget)
|
||||||
parts.sunkenNormal()->getBitmapN()->height(),
|
parts.sunkenNormal()->getBitmapN()->height(),
|
||||||
parts.sunkenNormal()->getBitmapE()->width(),
|
parts.sunkenNormal()->getBitmapE()->width(),
|
||||||
parts.sunkenNormal()->getBitmapS()->height());
|
parts.sunkenNormal()->getBitmapS()->height());
|
||||||
|
widget->setChildSpacing(3 * scale);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kGridWidget:
|
case kGridWidget:
|
||||||
|
|
@ -650,17 +651,6 @@ void SkinTheme::initWidget(Widget* widget)
|
||||||
else {
|
else {
|
||||||
BORDER4(4 * scale, 2 * scale, 1 * scale, 2 * scale);
|
BORDER4(4 * scale, 2 * scale, 1 * scale, 2 * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget->hasText()) {
|
|
||||||
gfx::Border border = widget->border();
|
|
||||||
|
|
||||||
if (widget->getAlign() & TOP)
|
|
||||||
border.top(widget->getTextHeight());
|
|
||||||
else if (widget->getAlign() & BOTTOM)
|
|
||||||
border.bottom(widget->getTextHeight());
|
|
||||||
|
|
||||||
widget->setBorder(border);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kSliderWidget:
|
case kSliderWidget:
|
||||||
|
|
@ -923,8 +913,9 @@ void SkinTheme::paintEntry(PaintEvent& ev)
|
||||||
bg);
|
bg);
|
||||||
|
|
||||||
// Draw the text
|
// Draw the text
|
||||||
x = bounds.x + widget->border().left();
|
bounds = widget->getEntryTextBounds();
|
||||||
y = bounds.y + bounds.h/2 - widget->getTextHeight()/2;
|
x = bounds.x;
|
||||||
|
y = bounds.y;
|
||||||
|
|
||||||
base::utf8_const_iterator utf8_it = base::utf8_const_iterator(textString.begin());
|
base::utf8_const_iterator utf8_it = base::utf8_const_iterator(textString.begin());
|
||||||
int textlen = base::utf8_length(textString);
|
int textlen = base::utf8_length(textString);
|
||||||
|
|
@ -954,7 +945,7 @@ void SkinTheme::paintEntry(PaintEvent& ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
w = g->measureChar(ch).w;
|
w = g->measureChar(ch).w;
|
||||||
if (x+w > bounds.x2()-3)
|
if (x+w > bounds.x2()-widget->childSpacing()*guiscale())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
caret_x = x;
|
caret_x = x;
|
||||||
|
|
@ -969,7 +960,7 @@ void SkinTheme::paintEntry(PaintEvent& ev)
|
||||||
// Draw suffix if there is enough space
|
// Draw suffix if there is enough space
|
||||||
if (!widget->getSuffix().empty()) {
|
if (!widget->getSuffix().empty()) {
|
||||||
Rect sufBounds(x, y,
|
Rect sufBounds(x, y,
|
||||||
bounds.x2()-3*guiscale()-x,
|
bounds.x2()-widget->childSpacing()*guiscale()-x,
|
||||||
widget->getTextHeight());
|
widget->getTextHeight());
|
||||||
IntersectClip clip(g, sufBounds);
|
IntersectClip clip(g, sufBounds);
|
||||||
if (clip) {
|
if (clip) {
|
||||||
|
|
@ -1228,22 +1219,27 @@ void SkinTheme::paintSeparator(ui::PaintEvent& ev)
|
||||||
// background
|
// background
|
||||||
g->fillRect(BGCOLOR, bounds);
|
g->fillRect(BGCOLOR, bounds);
|
||||||
|
|
||||||
if (widget->getAlign() & HORIZONTAL)
|
if (widget->getAlign() & HORIZONTAL) {
|
||||||
drawHline(g, bounds, parts.separatorHorz().get());
|
int h = parts.separatorHorz()->getBitmap(0)->height();
|
||||||
|
drawHline(g, gfx::Rect(bounds.x, bounds.y+bounds.h/2-h/2,
|
||||||
|
bounds.w, h),
|
||||||
|
parts.separatorHorz().get());
|
||||||
|
}
|
||||||
|
|
||||||
if (widget->getAlign() & VERTICAL)
|
if (widget->getAlign() & VERTICAL) {
|
||||||
drawVline(g, bounds, parts.separatorVert().get());
|
int w = parts.separatorVert()->getBitmap(0)->width();
|
||||||
|
drawVline(g, gfx::Rect(bounds.x+bounds.w/2-w/2, bounds.y,
|
||||||
|
w, bounds.h),
|
||||||
|
parts.separatorVert().get());
|
||||||
|
}
|
||||||
|
|
||||||
// text
|
// text
|
||||||
if (widget->hasText()) {
|
if (widget->hasText()) {
|
||||||
int h = widget->getTextHeight();
|
int h = widget->getTextHeight();
|
||||||
Rect r(
|
Rect r(
|
||||||
Point(
|
bounds.x + widget->border().left()/2 + h/2,
|
||||||
bounds.x + widget->border().left()/2 + h/2,
|
bounds.y + bounds.h/2 - h/2,
|
||||||
bounds.y + widget->border().top()/2 - h/2),
|
widget->getTextWidth(), h);
|
||||||
Point(
|
|
||||||
bounds.x2() - widget->border().right()/2 - h,
|
|
||||||
bounds.y2() - widget->border().bottom()/2 + h));
|
|
||||||
|
|
||||||
drawTextString(g, NULL,
|
drawTextString(g, NULL,
|
||||||
colors.separatorLabel(), BGCOLOR,
|
colors.separatorLabel(), BGCOLOR,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include "app/ui/button_set.h"
|
#include "app/ui/button_set.h"
|
||||||
#include "app/ui/color_button.h"
|
#include "app/ui/color_button.h"
|
||||||
#include "app/ui/drop_down_button.h"
|
#include "app/ui/drop_down_button.h"
|
||||||
|
#include "app/ui/search_entry.h"
|
||||||
#include "app/ui/skin/skin_style_property.h"
|
#include "app/ui/skin/skin_style_property.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "app/widget_not_found.h"
|
#include "app/widget_not_found.h"
|
||||||
|
|
@ -466,6 +467,10 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (elem_name == "search") {
|
||||||
|
if (!widget)
|
||||||
|
widget = new SearchEntry;
|
||||||
|
}
|
||||||
|
|
||||||
// Was the widget created?
|
// Was the widget created?
|
||||||
if (widget)
|
if (widget)
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ static std::string convert_type(const std::string& name)
|
||||||
if (name == "listbox") return "ui::ListBox";
|
if (name == "listbox") return "ui::ListBox";
|
||||||
if (name == "panel") return "ui::Panel";
|
if (name == "panel") return "ui::Panel";
|
||||||
if (name == "radio") return "ui::RadioButton";
|
if (name == "radio") return "ui::RadioButton";
|
||||||
|
if (name == "search") return "app::SearchEntry";
|
||||||
if (name == "slider") return "ui::Slider";
|
if (name == "slider") return "ui::Slider";
|
||||||
if (name == "splitter") return "ui::Splitter";
|
if (name == "splitter") return "ui::Splitter";
|
||||||
if (name == "vbox") return "ui::VBox";
|
if (name == "vbox") return "ui::VBox";
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,11 @@ void Entry::getEntryThemeInfo(int* scroll, int* caret, int* state,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx::Rect Entry::getEntryTextBounds() const
|
||||||
|
{
|
||||||
|
return onGetEntryTextBounds();
|
||||||
|
}
|
||||||
|
|
||||||
bool Entry::onProcessMessage(Message* msg)
|
bool Entry::onProcessMessage(Message* msg)
|
||||||
{
|
{
|
||||||
switch (msg->type()) {
|
switch (msg->type()) {
|
||||||
|
|
@ -454,27 +459,37 @@ void Entry::onChange()
|
||||||
Change();
|
Change();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gfx::Rect Entry::onGetEntryTextBounds() const
|
||||||
|
{
|
||||||
|
gfx::Rect bounds = getClientBounds();
|
||||||
|
bounds.x += border().left();
|
||||||
|
bounds.y += bounds.h/2 - getTextHeight()/2;
|
||||||
|
bounds.w -= border().width();
|
||||||
|
bounds.h = getTextHeight();
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
int Entry::getCaretFromMouse(MouseMessage* mousemsg)
|
int Entry::getCaretFromMouse(MouseMessage* mousemsg)
|
||||||
{
|
{
|
||||||
base::utf8_const_iterator utf8_begin = base::utf8_const_iterator(getText().begin());
|
base::utf8_const_iterator utf8_begin = base::utf8_const_iterator(getText().begin());
|
||||||
base::utf8_const_iterator utf8_end = base::utf8_const_iterator(getText().end());
|
base::utf8_const_iterator utf8_end = base::utf8_const_iterator(getText().end());
|
||||||
int c, x, w, mx, caret = m_caret;
|
int caret = m_caret;
|
||||||
int textlen = base::utf8_length(getText());
|
int textlen = base::utf8_length(getText());
|
||||||
|
gfx::Rect bounds = getEntryTextBounds().offset(getBounds().getOrigin());
|
||||||
|
|
||||||
mx = mousemsg->position().x;
|
int mx = mousemsg->position().x;
|
||||||
mx = MID(getBounds().x+border().left(),
|
mx = MID(bounds.x, mx, bounds.x2()-1);
|
||||||
mx,
|
|
||||||
getBounds().x2()-border().right()-1);
|
|
||||||
|
|
||||||
x = getBounds().x + border().left();
|
int x = bounds.x;
|
||||||
|
|
||||||
base::utf8_const_iterator utf8_it =
|
base::utf8_const_iterator utf8_it =
|
||||||
(m_scroll < textlen ?
|
(m_scroll < textlen ?
|
||||||
utf8_begin + m_scroll:
|
utf8_begin + m_scroll:
|
||||||
utf8_end);
|
utf8_end);
|
||||||
|
|
||||||
for (c=m_scroll; utf8_it != utf8_end; ++c, ++utf8_it) {
|
int c = m_scroll;
|
||||||
w = getFont()->charWidth(*utf8_it);
|
for (; utf8_it != utf8_end; ++c, ++utf8_it) {
|
||||||
|
int w = getFont()->charWidth(*utf8_it);
|
||||||
if (x+w >= getBounds().x2()-border().right())
|
if (x+w >= getBounds().x2()-border().right())
|
||||||
break;
|
break;
|
||||||
if ((mx >= x) && (mx < x+w)) {
|
if ((mx >= x) && (mx < x+w)) {
|
||||||
|
|
@ -485,8 +500,7 @@ int Entry::getCaretFromMouse(MouseMessage* mousemsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utf8_it == utf8_end) {
|
if (utf8_it == utf8_end) {
|
||||||
if ((mx >= x) &&
|
if ((mx >= x) && (mx < bounds.x2())) {
|
||||||
(mx <= getBounds().x2()-border().right()-1)) {
|
|
||||||
caret = c;
|
caret = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ namespace ui {
|
||||||
// for themes
|
// for themes
|
||||||
void getEntryThemeInfo(int* scroll, int* caret, int* state,
|
void getEntryThemeInfo(int* scroll, int* caret, int* state,
|
||||||
int* selbeg, int* selend);
|
int* selbeg, int* selend);
|
||||||
|
gfx::Rect getEntryTextBounds() const;
|
||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
Signal0<void> Change;
|
Signal0<void> Change;
|
||||||
|
|
@ -53,6 +54,7 @@ namespace ui {
|
||||||
|
|
||||||
// New Events
|
// New Events
|
||||||
virtual void onChange();
|
virtual void onChange();
|
||||||
|
virtual gfx::Rect onGetEntryTextBounds() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class EntryCmd {
|
enum class EntryCmd {
|
||||||
|
|
|
||||||
|
|
@ -45,8 +45,10 @@ void Separator::onPreferredSize(PreferredSizeEvent& ev)
|
||||||
maxSize.h = MAX(maxSize.h, reqSize.h);
|
maxSize.h = MAX(maxSize.h, reqSize.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasText())
|
if (hasText()) {
|
||||||
maxSize.w = MAX(maxSize.w, getTextWidth());
|
maxSize.w = MAX(maxSize.w, getTextWidth());
|
||||||
|
maxSize.h = MAX(maxSize.h, getTextHeight());
|
||||||
|
}
|
||||||
|
|
||||||
int w = maxSize.w + border().width();
|
int w = maxSize.w + border().width();
|
||||||
int h = maxSize.h + border().height();
|
int h = maxSize.h + border().height();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue