mirror of https://github.com/aseprite/aseprite.git
Add search field on Font Popup
Added support to set child visibility property to ListBox items.
This commit is contained in:
parent
76485d1e8a
commit
b6cf0f218c
|
@ -118,7 +118,6 @@ frames = Frames:
|
||||||
pixel_ratio = Apply pixel ratio
|
pixel_ratio = Apply pixel ratio
|
||||||
|
|
||||||
[font_popup]
|
[font_popup]
|
||||||
available_fonts = Available Fonts:
|
|
||||||
load = Load
|
load = Load
|
||||||
|
|
||||||
[frame_properties]
|
[frame_properties]
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<!-- Aseprite -->
|
<!-- Aseprite -->
|
||||||
<!-- Copyright (C) 2015-2016 by David Capello -->
|
<!-- Copyright (C) 2015-2017 by David Capello -->
|
||||||
<gui>
|
<gui>
|
||||||
<vbox id="font_popup">
|
<vbox id="font_popup">
|
||||||
<label text="@.available_fonts" />
|
<search id="search" magnet="true" />
|
||||||
<view id="view" expansive="true" />
|
<view id="view" expansive="true" />
|
||||||
<hbox>
|
<hbox>
|
||||||
<boxfiller />
|
<boxfiller />
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "app/commands/command.h"
|
#include "app/commands/command.h"
|
||||||
#include "app/context.h"
|
#include "app/context.h"
|
||||||
#include "app/file_selector.h"
|
#include "app/file_selector.h"
|
||||||
|
#include "app/match_words.h"
|
||||||
#include "app/resource_finder.h"
|
#include "app/resource_finder.h"
|
||||||
#include "app/tools/tool.h"
|
#include "app/tools/tool.h"
|
||||||
#include "app/tools/tool_box.h"
|
#include "app/tools/tool_box.h"
|
||||||
|
@ -487,8 +488,7 @@ private:
|
||||||
void fillSearchList(const std::string& search) {
|
void fillSearchList(const std::string& search) {
|
||||||
deleteList(searchList());
|
deleteList(searchList());
|
||||||
|
|
||||||
std::vector<std::string> parts;
|
MatchWords match(search);
|
||||||
base::split_string(base::string_to_lower(search), parts, " ");
|
|
||||||
|
|
||||||
ListBox* listBoxes[] = { menus(), commands(), tools(), actions() };
|
ListBox* listBoxes[] = { menus(), commands(), tools(), actions() };
|
||||||
int sectionIdx = 0; // index 0 is menus
|
int sectionIdx = 0; // index 0 is menus
|
||||||
|
@ -498,31 +498,24 @@ private:
|
||||||
for (auto item : listBox->children()) {
|
for (auto item : listBox->children()) {
|
||||||
if (KeyItem* keyItem = dynamic_cast<KeyItem*>(item)) {
|
if (KeyItem* keyItem = dynamic_cast<KeyItem*>(item)) {
|
||||||
std::string itemText = keyItem->searchableText();
|
std::string itemText = keyItem->searchableText();
|
||||||
std::string lowerItemText = base::string_to_lower(itemText);
|
if (!match(itemText))
|
||||||
int matches = 0;
|
continue;
|
||||||
|
|
||||||
for (const auto& part : parts) {
|
if (!group) {
|
||||||
if (lowerItemText.find(part) != std::string::npos)
|
group = new Separator(
|
||||||
++matches;
|
section()->children()[sectionIdx]->text(), HORIZONTAL);
|
||||||
|
group->setStyle(SkinTheme::instance()->styles.separatorInView());
|
||||||
|
|
||||||
|
searchList()->addChild(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matches == int(parts.size())) {
|
KeyItem* copyItem =
|
||||||
if (!group) {
|
new KeyItem(itemText,
|
||||||
group = new Separator(
|
keyItem->key(),
|
||||||
section()->children()[sectionIdx]->text(), HORIZONTAL);
|
keyItem->menuitem(), 0);
|
||||||
group->setStyle(SkinTheme::instance()->styles.separatorInView());
|
|
||||||
|
|
||||||
searchList()->addChild(group);
|
m_allKeyItems.push_back(copyItem);
|
||||||
}
|
searchList()->addChild(copyItem);
|
||||||
|
|
||||||
KeyItem* copyItem =
|
|
||||||
new KeyItem(itemText,
|
|
||||||
keyItem->key(),
|
|
||||||
keyItem->menuitem(), 0);
|
|
||||||
|
|
||||||
m_allKeyItems.push_back(copyItem);
|
|
||||||
searchList()->addChild(copyItem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2017 David Capello
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_MATCH_WORDS_H_INCLUDED
|
||||||
|
#define APP_MATCH_WORDS_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base/split_string.h"
|
||||||
|
#include "base/string.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class MatchWords {
|
||||||
|
public:
|
||||||
|
MatchWords(const std::string& search) {
|
||||||
|
base::split_string(base::string_to_lower(search),
|
||||||
|
m_parts, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(const std::string& item) {
|
||||||
|
std::string lowerItem = base::string_to_lower(item);
|
||||||
|
std::size_t matches = 0;
|
||||||
|
|
||||||
|
for (const auto& part : m_parts) {
|
||||||
|
if (lowerItem.find(part) != std::string::npos)
|
||||||
|
++matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (matches == m_parts.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_parts;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,6 +14,8 @@
|
||||||
#include "app/commands/commands.h"
|
#include "app/commands/commands.h"
|
||||||
#include "app/console.h"
|
#include "app/console.h"
|
||||||
#include "app/font_path.h"
|
#include "app/font_path.h"
|
||||||
|
#include "app/match_words.h"
|
||||||
|
#include "app/ui/search_entry.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "app/ui_context.h"
|
#include "app/ui_context.h"
|
||||||
#include "app/util/freetype_utils.h"
|
#include "app/util/freetype_utils.h"
|
||||||
|
@ -137,6 +139,7 @@ FontPopup::FontPopup()
|
||||||
|
|
||||||
addChild(m_popup);
|
addChild(m_popup);
|
||||||
|
|
||||||
|
m_popup->search()->Change.connect(base::Bind<void>(&FontPopup::onSearchChange, this));
|
||||||
m_popup->loadFont()->Click.connect(base::Bind<void>(&FontPopup::onLoadFont, this));
|
m_popup->loadFont()->Click.connect(base::Bind<void>(&FontPopup::onLoadFont, this));
|
||||||
m_listBox.setFocusMagnet(true);
|
m_listBox.setFocusMagnet(true);
|
||||||
m_listBox.Change.connect(base::Bind<void>(&FontPopup::onChangeFont, this));
|
m_listBox.Change.connect(base::Bind<void>(&FontPopup::onChangeFont, this));
|
||||||
|
@ -190,6 +193,23 @@ void FontPopup::showPopup(const gfx::Rect& bounds)
|
||||||
openWindow();
|
openWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FontPopup::onSearchChange()
|
||||||
|
{
|
||||||
|
std::string searchText = m_popup->search()->text();
|
||||||
|
Widget* firstItem = nullptr;
|
||||||
|
|
||||||
|
MatchWords match(searchText);
|
||||||
|
for (auto child : m_listBox.children()) {
|
||||||
|
bool visible = match(child->text());
|
||||||
|
if (visible && !firstItem)
|
||||||
|
firstItem = child;
|
||||||
|
child->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_listBox.selectChild(firstItem);
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
void FontPopup::onChangeFont()
|
void FontPopup::onChangeFont()
|
||||||
{
|
{
|
||||||
m_popup->loadFont()->setEnabled(true);
|
m_popup->loadFont()->setEnabled(true);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite
|
// Aseprite
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This program is distributed under the terms of
|
// This program is distributed under the terms of
|
||||||
// the End-User License Agreement for Aseprite.
|
// the End-User License Agreement for Aseprite.
|
||||||
|
@ -31,6 +31,7 @@ namespace app {
|
||||||
obs::signal<void(const std::string&)> Load;
|
obs::signal<void(const std::string&)> Load;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void onSearchChange();
|
||||||
void onChangeFont();
|
void onChangeFont();
|
||||||
void onLoadFont();
|
void onLoadFont();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
// Read LICENSE.txt for more information.
|
// Read LICENSE.txt for more information.
|
||||||
|
@ -270,33 +270,42 @@ bool ListBox::onProcessMessage(Message* msg)
|
||||||
case kKeyDownMessage:
|
case kKeyDownMessage:
|
||||||
if (hasFocus() && !children().empty()) {
|
if (hasFocus() && !children().empty()) {
|
||||||
int select = getSelectedIndex();
|
int select = getSelectedIndex();
|
||||||
View* view = View::getView(this);
|
|
||||||
int bottom = MAX(0, children().size()-1);
|
int bottom = MAX(0, children().size()-1);
|
||||||
|
View* view = View::getView(this);
|
||||||
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
||||||
|
KeyScancode scancode = keymsg->scancode();
|
||||||
|
|
||||||
switch (keymsg->scancode()) {
|
if (keymsg->onlyCmdPressed()) {
|
||||||
|
if (scancode == kKeyUp) scancode = kKeyHome;
|
||||||
|
if (scancode == kKeyDown) scancode = kKeyEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (scancode) {
|
||||||
case kKeyUp:
|
case kKeyUp:
|
||||||
// Select previous element.
|
// Select previous element.
|
||||||
if (select >= 0)
|
if (select >= 0) {
|
||||||
select--;
|
select = advanceIndexThroughVisibleItems(select, -1, true);
|
||||||
|
}
|
||||||
// Or select the bottom of the list if there is no
|
// Or select the bottom of the list if there is no
|
||||||
// selected item.
|
// selected item.
|
||||||
else
|
else {
|
||||||
select = bottom;
|
select = advanceIndexThroughVisibleItems(bottom+1, -1, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case kKeyDown:
|
case kKeyDown:
|
||||||
select++;
|
select = advanceIndexThroughVisibleItems(select, +1, true);
|
||||||
break;
|
break;
|
||||||
case kKeyHome:
|
case kKeyHome:
|
||||||
select = 0;
|
select = advanceIndexThroughVisibleItems(-1, +1, false);
|
||||||
break;
|
break;
|
||||||
case kKeyEnd:
|
case kKeyEnd:
|
||||||
select = bottom;
|
select = advanceIndexThroughVisibleItems(bottom+1, -1, false);
|
||||||
break;
|
break;
|
||||||
case kKeyPageUp:
|
case kKeyPageUp:
|
||||||
if (view) {
|
if (view) {
|
||||||
gfx::Rect vp = view->viewportBounds();
|
gfx::Rect vp = view->viewportBounds();
|
||||||
select -= vp.h / textHeight();
|
select = advanceIndexThroughVisibleItems(
|
||||||
|
select, -vp.h / textHeight(), false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
select = 0;
|
select = 0;
|
||||||
|
@ -304,10 +313,12 @@ bool ListBox::onProcessMessage(Message* msg)
|
||||||
case kKeyPageDown:
|
case kKeyPageDown:
|
||||||
if (view) {
|
if (view) {
|
||||||
gfx::Rect vp = view->viewportBounds();
|
gfx::Rect vp = view->viewportBounds();
|
||||||
select += vp.h / textHeight();
|
select = advanceIndexThroughVisibleItems(
|
||||||
|
select, +vp.h / textHeight(), false);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
select = bottom;
|
select = bottom;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case kKeyLeft:
|
case kKeyLeft:
|
||||||
case kKeyRight:
|
case kKeyRight:
|
||||||
|
@ -350,23 +361,33 @@ void ListBox::onResize(ResizeEvent& ev)
|
||||||
Rect cpos = childrenBounds();
|
Rect cpos = childrenBounds();
|
||||||
|
|
||||||
for (auto child : children()) {
|
for (auto child : children()) {
|
||||||
|
if (child->hasFlags(HIDDEN))
|
||||||
|
continue;
|
||||||
|
|
||||||
cpos.h = child->sizeHint().h;
|
cpos.h = child->sizeHint().h;
|
||||||
child->setBounds(cpos);
|
child->setBounds(cpos);
|
||||||
|
|
||||||
cpos.y += child->bounds().h + this->childSpacing();
|
cpos.y += child->bounds().h + childSpacing();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListBox::onSizeHint(SizeHintEvent& ev)
|
void ListBox::onSizeHint(SizeHintEvent& ev)
|
||||||
{
|
{
|
||||||
int w = 0, h = 0;
|
int w = 0, h = 0;
|
||||||
|
int visibles = 0;
|
||||||
|
|
||||||
UI_FOREACH_WIDGET_WITH_END(children(), it, end) {
|
for (auto child : children()) {
|
||||||
Size reqSize = (*it)->sizeHint();
|
if (child->hasFlags(HIDDEN))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Size reqSize = child->sizeHint();
|
||||||
|
|
||||||
w = MAX(w, reqSize.w);
|
w = MAX(w, reqSize.w);
|
||||||
h += reqSize.h + (it+1 != end ? this->childSpacing(): 0);
|
h += reqSize.h;
|
||||||
|
++visibles;
|
||||||
}
|
}
|
||||||
|
if (visibles > 1)
|
||||||
|
h += childSpacing() * (visibles-1);
|
||||||
|
|
||||||
w += border().width();
|
w += border().width();
|
||||||
h += border().height();
|
h += border().height();
|
||||||
|
@ -384,4 +405,45 @@ void ListBox::onDoubleClickItem()
|
||||||
DoubleClickItem();
|
DoubleClickItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ListBox::advanceIndexThroughVisibleItems(
|
||||||
|
int startIndex, int delta, const bool loop)
|
||||||
|
{
|
||||||
|
const int bottom = MAX(0, children().size()-1);
|
||||||
|
const int sgn = SGN(delta);
|
||||||
|
int index = startIndex;
|
||||||
|
|
||||||
|
startIndex = MID(0, startIndex, bottom);
|
||||||
|
int lastVisibleIndex = startIndex;
|
||||||
|
|
||||||
|
bool cycle = false;
|
||||||
|
|
||||||
|
while (delta) {
|
||||||
|
index += sgn;
|
||||||
|
|
||||||
|
if (cycle && index == startIndex) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (index < 0) {
|
||||||
|
if (!loop)
|
||||||
|
break;
|
||||||
|
index = bottom-sgn;
|
||||||
|
cycle = true;
|
||||||
|
}
|
||||||
|
else if (index > bottom) {
|
||||||
|
if (!loop)
|
||||||
|
break;
|
||||||
|
index = 0-sgn;
|
||||||
|
cycle = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Widget* item = getChildByIndex(index);
|
||||||
|
if (item && !item->hasFlags(HIDDEN)) {
|
||||||
|
lastVisibleIndex = index;
|
||||||
|
delta -= sgn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lastVisibleIndex;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite UI Library
|
// Aseprite UI Library
|
||||||
// Copyright (C) 2001-2016 David Capello
|
// Copyright (C) 2001-2017 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
// Read LICENSE.txt for more information.
|
// Read LICENSE.txt for more information.
|
||||||
|
@ -50,6 +50,9 @@ namespace ui {
|
||||||
int getChildIndex(Widget* item);
|
int getChildIndex(Widget* item);
|
||||||
Widget* getChildByIndex(int index);
|
Widget* getChildByIndex(int index);
|
||||||
|
|
||||||
|
int advanceIndexThroughVisibleItems(
|
||||||
|
int startIndex, int delta, const bool loop);
|
||||||
|
|
||||||
// True if this listbox accepts selecting multiple items at the
|
// True if this listbox accepts selecting multiple items at the
|
||||||
// same time.
|
// same time.
|
||||||
bool m_multiselect;
|
bool m_multiselect;
|
||||||
|
|
Loading…
Reference in New Issue