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="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_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> | ||||
| 
 | ||||
|   <stylesheet> | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
|     <vbox> | ||||
|       <hbox expansive="true"> | ||||
|         <vbox> | ||||
|           <search id="search" magnet="true" /> | ||||
|           <view width="80" expansive="true"> | ||||
|             <listbox id="section" expansive="true" /> | ||||
|           </view> | ||||
|  | @ -14,6 +15,9 @@ | |||
|           <button text="&Reset" id="reset_button" /> | ||||
|         </vbox> | ||||
|         <vbox expansive="true"> | ||||
|           <view id="search_view" expansive="true"> | ||||
|             <listbox id="search_list" /> | ||||
|           </view> | ||||
|           <view id="menus_view" expansive="true"> | ||||
|             <listbox id="menus" /> | ||||
|           </view> | ||||
|  |  | |||
|  | @ -381,6 +381,7 @@ add_library(app-lib | |||
|   ui/preview_editor.cpp | ||||
|   ui/recent_listbox.cpp | ||||
|   ui/resources_listbox.cpp | ||||
|   ui/search_entry.cpp | ||||
|   ui/select_accelerator.cpp | ||||
|   ui/skin/button_icon_impl.cpp | ||||
|   ui/skin/skin_part.cpp | ||||
|  |  | |||
|  | @ -18,16 +18,21 @@ | |||
| #include "app/tools/tool.h" | ||||
| #include "app/ui/app_menuitem.h" | ||||
| #include "app/ui/keyboard_shortcuts.h" | ||||
| #include "app/ui/search_entry.h" | ||||
| #include "app/ui/select_accelerator.h" | ||||
| #include "app/ui/skin/skin_theme.h" | ||||
| #include "base/bind.h" | ||||
| #include "base/fs.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/listitem.h" | ||||
| #include "ui/paint_event.h" | ||||
| #include "ui/preferred_size_event.h" | ||||
| #include "ui/resize_event.h" | ||||
| #include "ui/separator.h" | ||||
| 
 | ||||
| #include "keyboard_shortcuts.xml.h" | ||||
| 
 | ||||
|  | @ -55,6 +60,8 @@ public: | |||
|     setBorder(border); | ||||
|   } | ||||
| 
 | ||||
|   Key* key() { return m_key; } | ||||
| 
 | ||||
|   void restoreKeys() { | ||||
|     if (m_key && m_keyOrig) | ||||
|       *m_key = *m_keyOrig; | ||||
|  | @ -280,7 +287,7 @@ private: | |||
| 
 | ||||
| class KeyboardShortcutsWindow : public app::gen::KeyboardShortcuts { | ||||
| public: | ||||
|   KeyboardShortcutsWindow() { | ||||
|   KeyboardShortcutsWindow() : m_searchChange(false) { | ||||
|     setAutoRemap(false); | ||||
| 
 | ||||
|     section()->addChild(new ListItem("Menus")); | ||||
|  | @ -288,6 +295,7 @@ public: | |||
|     section()->addChild(new ListItem("Tools")); | ||||
|     section()->addChild(new ListItem("Action Modifiers")); | ||||
| 
 | ||||
|     search()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSearchChange, this)); | ||||
|     section()->Change.connect(Bind<void>(&KeyboardShortcutsWindow::onSectionChange, this)); | ||||
|     importButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onImport, this)); | ||||
|     exportButton()->Click.connect(Bind<void>(&KeyboardShortcutsWindow::onExport, this)); | ||||
|  | @ -304,6 +312,8 @@ public: | |||
| 
 | ||||
| private: | ||||
|   void deleteAllKeyItems() { | ||||
|     while (searchList()->getLastChild()) | ||||
|       searchList()->removeChild(searchList()->getLastChild()); | ||||
|     while (menus()->getLastChild()) | ||||
|       menus()->removeChild(menus()->getLastChild()); | ||||
|     while (commands()->getLastChild()) | ||||
|  | @ -375,12 +385,78 @@ private: | |||
|     this->actions()->sortItems(); | ||||
| 
 | ||||
|     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() { | ||||
|     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); | ||||
|     commandsView()->setVisible(section == 1); | ||||
|     toolsView()->setVisible(section == 2); | ||||
|  | @ -438,6 +514,7 @@ private: | |||
|   } | ||||
| 
 | ||||
|   std::vector<KeyItem*> m_allKeyItems; | ||||
|   bool m_searchChange; | ||||
| }; | ||||
| 
 | ||||
| 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()->getBitmapE()->width(), | ||||
|         parts.sunkenNormal()->getBitmapS()->height()); | ||||
|       widget->setChildSpacing(3 * scale); | ||||
|       break; | ||||
| 
 | ||||
|     case kGridWidget: | ||||
|  | @ -650,17 +651,6 @@ void SkinTheme::initWidget(Widget* widget) | |||
|       else { | ||||
|         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; | ||||
| 
 | ||||
|     case kSliderWidget: | ||||
|  | @ -923,8 +913,9 @@ void SkinTheme::paintEntry(PaintEvent& ev) | |||
|     bg); | ||||
| 
 | ||||
|   // Draw the text
 | ||||
|   x = bounds.x + widget->border().left(); | ||||
|   y = bounds.y + bounds.h/2 - widget->getTextHeight()/2; | ||||
|   bounds = widget->getEntryTextBounds(); | ||||
|   x = bounds.x; | ||||
|   y = bounds.y; | ||||
| 
 | ||||
|   base::utf8_const_iterator utf8_it = base::utf8_const_iterator(textString.begin()); | ||||
|   int textlen = base::utf8_length(textString); | ||||
|  | @ -954,7 +945,7 @@ void SkinTheme::paintEntry(PaintEvent& ev) | |||
|     } | ||||
| 
 | ||||
|     w = g->measureChar(ch).w; | ||||
|     if (x+w > bounds.x2()-3) | ||||
|     if (x+w > bounds.x2()-widget->childSpacing()*guiscale()) | ||||
|       return; | ||||
| 
 | ||||
|     caret_x = x; | ||||
|  | @ -969,7 +960,7 @@ void SkinTheme::paintEntry(PaintEvent& ev) | |||
|   // Draw suffix if there is enough space
 | ||||
|   if (!widget->getSuffix().empty()) { | ||||
|     Rect sufBounds(x, y, | ||||
|                    bounds.x2()-3*guiscale()-x, | ||||
|                    bounds.x2()-widget->childSpacing()*guiscale()-x, | ||||
|                    widget->getTextHeight()); | ||||
|     IntersectClip clip(g, sufBounds); | ||||
|     if (clip) { | ||||
|  | @ -1228,22 +1219,27 @@ void SkinTheme::paintSeparator(ui::PaintEvent& ev) | |||
|   // background
 | ||||
|   g->fillRect(BGCOLOR, bounds); | ||||
| 
 | ||||
|   if (widget->getAlign() & HORIZONTAL) | ||||
|     drawHline(g, bounds, parts.separatorHorz().get()); | ||||
|   if (widget->getAlign() & HORIZONTAL) { | ||||
|     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) | ||||
|     drawVline(g, bounds, parts.separatorVert().get()); | ||||
|   if (widget->getAlign() & VERTICAL) { | ||||
|     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
 | ||||
|   if (widget->hasText()) { | ||||
|     int h = widget->getTextHeight(); | ||||
|     Rect r( | ||||
|       Point( | ||||
|       bounds.x + widget->border().left()/2 + h/2, | ||||
|         bounds.y + widget->border().top()/2 - h/2), | ||||
|       Point( | ||||
|         bounds.x2() - widget->border().right()/2 - h, | ||||
|         bounds.y2() - widget->border().bottom()/2 + h)); | ||||
|       bounds.y + bounds.h/2 - h/2, | ||||
|       widget->getTextWidth(), h); | ||||
| 
 | ||||
|     drawTextString(g, NULL, | ||||
|       colors.separatorLabel(), BGCOLOR, | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| #include "app/ui/button_set.h" | ||||
| #include "app/ui/color_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_theme.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?
 | ||||
|   if (widget) | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ static std::string convert_type(const std::string& name) | |||
|   if (name == "listbox") return "ui::ListBox"; | ||||
|   if (name == "panel") return "ui::Panel"; | ||||
|   if (name == "radio") return "ui::RadioButton"; | ||||
|   if (name == "search") return "app::SearchEntry"; | ||||
|   if (name == "slider") return "ui::Slider"; | ||||
|   if (name == "splitter") return "ui::Splitter"; | ||||
|   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) | ||||
| { | ||||
|   switch (msg->type()) { | ||||
|  | @ -454,27 +459,37 @@ void Entry::onChange() | |||
|   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) | ||||
| { | ||||
|   base::utf8_const_iterator utf8_begin = base::utf8_const_iterator(getText().begin()); | ||||
|   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()); | ||||
|   gfx::Rect bounds = getEntryTextBounds().offset(getBounds().getOrigin()); | ||||
| 
 | ||||
|   mx = mousemsg->position().x; | ||||
|   mx = MID(getBounds().x+border().left(), | ||||
|            mx, | ||||
|            getBounds().x2()-border().right()-1); | ||||
|   int mx = mousemsg->position().x; | ||||
|   mx = MID(bounds.x, mx, bounds.x2()-1); | ||||
| 
 | ||||
|   x = getBounds().x + border().left(); | ||||
|   int x = bounds.x; | ||||
| 
 | ||||
|   base::utf8_const_iterator utf8_it = | ||||
|     (m_scroll < textlen ? | ||||
|       utf8_begin + m_scroll: | ||||
|       utf8_end); | ||||
| 
 | ||||
|   for (c=m_scroll; utf8_it != utf8_end; ++c, ++utf8_it) { | ||||
|     w = getFont()->charWidth(*utf8_it); | ||||
|   int c = m_scroll; | ||||
|   for (; utf8_it != utf8_end; ++c, ++utf8_it) { | ||||
|     int w = getFont()->charWidth(*utf8_it); | ||||
|     if (x+w >= getBounds().x2()-border().right()) | ||||
|       break; | ||||
|     if ((mx >= x) && (mx < x+w)) { | ||||
|  | @ -485,8 +500,7 @@ int Entry::getCaretFromMouse(MouseMessage* mousemsg) | |||
|   } | ||||
| 
 | ||||
|   if (utf8_it == utf8_end) { | ||||
|     if ((mx >= x) && | ||||
|         (mx <= getBounds().x2()-border().right()-1)) { | ||||
|     if ((mx >= x) && (mx < bounds.x2())) { | ||||
|       caret = c; | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -40,6 +40,7 @@ namespace ui { | |||
|     // for themes
 | ||||
|     void getEntryThemeInfo(int* scroll, int* caret, int* state, | ||||
|                            int* selbeg, int* selend); | ||||
|     gfx::Rect getEntryTextBounds() const; | ||||
| 
 | ||||
|     // Signals
 | ||||
|     Signal0<void> Change; | ||||
|  | @ -53,6 +54,7 @@ namespace ui { | |||
| 
 | ||||
|     // New Events
 | ||||
|     virtual void onChange(); | ||||
|     virtual gfx::Rect onGetEntryTextBounds() const; | ||||
| 
 | ||||
|   private: | ||||
|     enum class EntryCmd { | ||||
|  |  | |||
|  | @ -45,8 +45,10 @@ void Separator::onPreferredSize(PreferredSizeEvent& ev) | |||
|     maxSize.h = MAX(maxSize.h, reqSize.h); | ||||
|   } | ||||
| 
 | ||||
|   if (hasText()) | ||||
|   if (hasText()) { | ||||
|     maxSize.w = MAX(maxSize.w, getTextWidth()); | ||||
|     maxSize.h = MAX(maxSize.h, getTextHeight()); | ||||
|   } | ||||
| 
 | ||||
|   int w = maxSize.w + border().width(); | ||||
|   int h = maxSize.h + border().height(); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue