Add possibility to pin/unpin recent items

This commit is contained in:
David Capello 2018-12-22 00:14:31 -03:00
parent 57a8bbdf19
commit 72313e1c48
9 changed files with 137 additions and 10 deletions

View File

@ -654,6 +654,15 @@
<style id="recent_file_detail" border="2" border-left="0" extends="recent_file">
<text color="disabled" align="left" x="2" />
</style>
<style id="recent_file_pin">
<background color="background" />
<background color="menuitem_hot_face" state="mouse" />
<background color="listitem_selected_face" state="selected" />
<icon part="unpinned" align="center middle" color="text" />
<icon part="unpinned" align="center middle" color="listitem_selected_text" state="selected" />
<icon part="pinned" align="center middle" color="text" state="focus" />
<icon part="pinned" align="center middle" color="listitem_selected_text" state="focus selected" />
</style>
<style id="news_item" border="2">
<background color="background" />
<background color="menuitem_hot_face" state="mouse" />

2
laf

@ -1 +1 @@
Subproject commit 950f62c1ccff7cf59c220e9016ead0845767e546
Subproject commit 3355825d61b8d0d92ffdea970fd9e1434bd4ecca

View File

@ -95,12 +95,20 @@ public:
return m_wasDragged;
}
bool isDragging() const {
return m_isDragging;
}
private:
void createFloatingOverlay() {
ASSERT(!m_floatingOverlay);
m_isDragging = true;
gfx::Size sz = getFloatingOverlaySize();
sz.w = std::max(1, sz.w);
sz.h = std::max(1, sz.h);
os::Surface* surface = os::instance()->createRgbaSurface(sz.w, sz.h);
{
@ -122,6 +130,7 @@ private:
void destroyFloatingOverlay() {
ui::OverlayManager::instance()->removeOverlay(m_floatingOverlay.get());
m_floatingOverlay.reset();
m_isDragging = false;
}
gfx::Size getFloatingOverlaySize() {
@ -129,7 +138,7 @@ private:
if (!view)
view = ui::View::getView(this->parent());
if (view)
return (view->viewportBounds() & this->bounds()).size();
return (view->viewportBounds().offset(view->viewScroll()) & this->bounds()).size();
else
return this->size();
}
@ -146,6 +155,8 @@ private:
// widget bounds.
bool m_createFloatingOverlay = false;
bool m_isDragging = false;
// True when the mouse button is released (drop operation) and we've
// dragged the widget to other position. Can be used to avoid
// triggering the default click operation by derived classes when

View File

@ -121,8 +121,6 @@ void EditorView::onSetViewScroll(const gfx::Point& pt)
void EditorView::onScrollRegion(ui::ScrollRegionEvent& ev)
{
View::onScrollRegion(ev);
gfx::Region& region = ev.region();
Editor* editor = this->editor();
ASSERT(editor);

View File

@ -17,8 +17,6 @@ namespace app {
void FileListView::onScrollRegion(ui::ScrollRegionEvent& ev)
{
View::onScrollRegion(ev);
if (auto fileList = dynamic_cast<FileList*>(attachedWidget())) {
gfx::Rect tbounds = fileList->thumbnailBounds();
if (!tbounds.isEmpty()) {

View File

@ -28,6 +28,7 @@
#include "ui/listitem.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/scroll_region_event.h"
#include "ui/size_hint_event.h"
#include "ui/system.h"
#include "ui/view.h"
@ -51,6 +52,16 @@ public:
}
const std::string& fullpath() const { return m_fullpath; }
bool pinned() const { return m_pinned; }
void pin() {
m_pinned = true;
invalidate();
}
void onScrollRegion(ui::ScrollRegionEvent& ev) {
ev.region() -= gfx::Region(pinBounds(bounds()));
}
protected:
void onInitTheme(InitThemeEvent& ev) override {
@ -72,6 +83,52 @@ protected:
ev.setSizeHint(gfx::Size(sz1.w+sz2.w, MAX(sz1.h, sz2.h)));
}
bool onProcessMessage(Message* msg) override {
switch (msg->type()) {
case kMouseDownMessage: {
const gfx::Point mousePos = static_cast<MouseMessage*>(msg)->position();
gfx::Rect rc = pinBounds(bounds());
rc.y = bounds().y;
rc.h = bounds().h;
if (rc.contains(mousePos)) {
m_pinned = !m_pinned;
invalidate();
auto parent = this->parent();
const auto& children = parent->children();
auto end = children.end();
auto moveTo = parent->firstChild();
if (m_pinned) {
for (auto it=children.begin(); it != end; ++it) {
if (*it == this || !static_cast<RecentFileItem*>(*it)->pinned()) {
moveTo = *it;
break;
}
}
}
else {
auto it = std::find(children.begin(), end, this);
if (it != end) {
auto prevIt = it++;
for (; it != end; prevIt=it++) {
if (!static_cast<RecentFileItem*>(*it)->pinned())
break;
}
moveTo = *prevIt;
}
}
if (this != moveTo) {
parent->moveChildTo(this, moveTo);
parent->layout();
}
return true;
}
break;
}
}
return DraggableWidget<LinkLabel>::onProcessMessage(msg);
}
void onPaint(PaintEvent& ev) override {
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
Graphics* g = ev.graphics();
@ -90,6 +147,17 @@ protected:
setTextQuiet(m_path.c_str());
theme->paintWidget(g, this, styleDetail, detailsBounds);
}
if (!isDragging() && (m_pinned || hasMouse())) {
ui::Style* pinStyle = theme->styles.recentFilePin();
const gfx::Rect pinBounds = this->pinBounds(bounds);
PaintWidgetPartInfo pi;
pi.styleFlags =
(isSelected() ? ui::Style::Layer::kSelected: 0) |
(m_pinned ? ui::Style::Layer::kFocus: 0) |
(hasMouse() ? ui::Style::Layer::kMouse: 0);
theme->paintWidgetPart(g, pinStyle, pinBounds, pi);
}
}
void onClick() override {
@ -107,14 +175,39 @@ protected:
}
void onFinalDrop() override {
if (wasDragged())
static_cast<RecentListBox*>(parent())->updateRecentListFromUIItems();
if (!wasDragged())
return;
// Pin all elements to keep the order
const auto& children = parent()->children();
for (auto it=children.rbegin(), end=children.rend(); it!=end; ++it) {
if (this == *it) {
for (; it!=end; ++it)
static_cast<RecentFileItem*>(*it)->pin();
break;
}
}
static_cast<RecentListBox*>(parent())->updateRecentListFromUIItems();
}
private:
gfx::Rect pinBounds(const gfx::Rect& bounds) {
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
ui::Style* pinStyle = theme->styles.recentFilePin();
ui::View* view = View::getView(parent());
const gfx::Size pinSize = theme->calcSizeHint(this, pinStyle);
const gfx::Rect vp = view->viewportBounds();
const gfx::Point scroll = view->viewScroll();
return gfx::Rect(scroll.x+bounds.x+vp.w-pinSize.w,
bounds.y+bounds.h/2-pinSize.h/2,
pinSize.w, pinSize.h);
}
std::string m_fullpath;
std::string m_name;
std::string m_path;
bool m_pinned = false;
};
//////////////////////////////////////////////////////////////////////
@ -156,6 +249,12 @@ void RecentListBox::updateRecentListFromUIItems()
onUpdateRecentListFromUIItems(paths);
}
void RecentListBox::onScrollRegion(ui::ScrollRegionEvent& ev)
{
for (auto item : children())
static_cast<RecentFileItem*>(item)->onScrollRegion(ev);
}
//////////////////////////////////////////////////////////////////////
// RecentFilesListBox

View File

@ -12,12 +12,14 @@
#include "base/paths.h"
#include "obs/connection.h"
#include "ui/listbox.h"
#include "ui/view.h"
namespace app {
class RecentFileItem;
class RecentListBox : public ui::ListBox {
class RecentListBox : public ui::ListBox,
public ui::ViewableWidget {
friend class RecentFileItem;
public:
RecentListBox();
@ -25,6 +27,9 @@ namespace app {
void updateRecentListFromUIItems();
protected:
// ui::ViewableWidget impl
virtual void onScrollRegion(ui::ScrollRegionEvent& ev);
virtual void onRebuildList() = 0;
virtual void onClick(const std::string& path) = 0;
virtual void onUpdateRecentListFromUIItems(const base::paths& paths) = 0;

View File

@ -356,7 +356,8 @@ void View::onSetViewScroll(const gfx::Point& pt)
void View::onScrollRegion(ScrollRegionEvent& ev)
{
// Do nothing
if (auto viewable = dynamic_cast<ViewableWidget*>(attachedWidget()))
viewable->onScrollRegion(ev);
}
void View::onScrollChange()

View File

@ -17,6 +17,12 @@
namespace ui {
class ScrollRegionEvent;
class ViewableWidget {
public:
virtual ~ViewableWidget() { }
virtual void onScrollRegion(ScrollRegionEvent& ev) = 0;
};
class View : public Widget
, public ScrollableViewDelegate {
public: