2015-12-15 21:53:15 +00:00
|
|
|
#include "Specter/FileBrowser.hpp"
|
|
|
|
#include "Specter/RootView.hpp"
|
|
|
|
|
|
|
|
namespace Specter
|
|
|
|
{
|
|
|
|
|
2015-12-30 02:50:56 +00:00
|
|
|
#define BROWSER_MARGIN 8
|
2015-12-20 04:39:09 +00:00
|
|
|
#define BROWSER_MIN_WIDTH 600
|
|
|
|
#define BROWSER_MIN_HEIGHT 300
|
2015-12-15 21:53:15 +00:00
|
|
|
|
|
|
|
static std::vector<HECL::SystemString> PathComponents(const HECL::SystemString& path)
|
|
|
|
{
|
|
|
|
std::vector<HECL::SystemString> ret;
|
|
|
|
HECL::SystemString sPath = path;
|
|
|
|
HECL::SanitizePath(sPath);
|
|
|
|
if (sPath.empty())
|
|
|
|
return ret;
|
|
|
|
auto it = sPath.cbegin();
|
|
|
|
if (*it == _S('/'))
|
|
|
|
{
|
2015-12-18 04:54:31 +00:00
|
|
|
ret.push_back(_S("/"));
|
2015-12-15 21:53:15 +00:00
|
|
|
++it;
|
|
|
|
}
|
|
|
|
HECL::SystemString comp;
|
|
|
|
for (; it != sPath.cend() ; ++it)
|
|
|
|
{
|
|
|
|
if (*it == _S('/'))
|
|
|
|
{
|
|
|
|
if (comp.empty())
|
|
|
|
continue;
|
|
|
|
ret.push_back(std::move(comp));
|
|
|
|
comp.clear();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
comp += *it;
|
|
|
|
}
|
|
|
|
if (comp.size())
|
|
|
|
ret.push_back(std::move(comp));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-12-22 01:33:27 +00:00
|
|
|
FileBrowser::FileBrowser(ViewResources& res, View& parentView, const std::string& title,
|
2015-12-30 22:04:58 +00:00
|
|
|
Type type, const HECL::SystemString& initialPath)
|
2015-12-20 04:39:09 +00:00
|
|
|
: ModalWindow(res, parentView, RectangleConstraint(BROWSER_MIN_WIDTH * res.pixelFactor(),
|
|
|
|
BROWSER_MIN_HEIGHT * res.pixelFactor(),
|
|
|
|
RectangleConstraint::Test::Minimum,
|
|
|
|
RectangleConstraint::Test::Minimum)),
|
2015-12-30 22:04:58 +00:00
|
|
|
m_type(type),
|
2015-12-22 01:33:27 +00:00
|
|
|
m_left(*this, res),
|
|
|
|
m_right(*this, res),
|
|
|
|
m_ok(*this, res, title),
|
|
|
|
m_cancel(*this, res),
|
2015-12-18 03:26:10 +00:00
|
|
|
m_fileFieldBind(*this)
|
2015-12-15 21:53:15 +00:00
|
|
|
{
|
|
|
|
commitResources(res);
|
|
|
|
setBackground({0,0,0,0.5});
|
|
|
|
|
2015-12-18 03:26:10 +00:00
|
|
|
m_fileField.m_view.reset(new TextField(res, *this, &m_fileFieldBind));
|
2015-12-23 00:25:46 +00:00
|
|
|
m_fileListing.m_view.reset(new Table(res, *this, &m_fileListingBind));
|
2015-12-30 22:04:58 +00:00
|
|
|
m_systemBookmarks.m_view.reset(new Table(res, *this, &m_systemBookmarkBind));
|
|
|
|
m_systemBookmarksLabel.reset(new TextView(res, *this, res.m_mainFont));
|
|
|
|
m_systemBookmarksLabel->typesetGlyphs("System Locations:", res.themeData().uiText());
|
|
|
|
m_projectBookmarks.m_view.reset(new Table(res, *this, &m_projectBookmarkBind));
|
|
|
|
m_projectBookmarksLabel.reset(new TextView(res, *this, res.m_mainFont));
|
|
|
|
m_projectBookmarksLabel->typesetGlyphs("Recent Projects:", res.themeData().uiText());
|
|
|
|
m_recentBookmarks.m_view.reset(new Table(res, *this, &m_recentBookmarkBind));
|
|
|
|
m_recentBookmarksLabel.reset(new TextView(res, *this, res.m_mainFont));
|
|
|
|
m_recentBookmarksLabel->typesetGlyphs("Recent Files:", res.themeData().uiText());
|
|
|
|
|
|
|
|
navigateToPath(initialPath);
|
2015-12-22 01:33:27 +00:00
|
|
|
|
|
|
|
m_split.m_view.reset(new SplitView(res, *this, SplitView::Axis::Vertical,
|
|
|
|
200 * res.pixelFactor(), 400 * res.pixelFactor()));
|
|
|
|
m_split.m_view->setContentView(0, &m_left);
|
|
|
|
m_split.m_view->setContentView(1, &m_right);
|
|
|
|
m_split.m_view->setSlide(0.2);
|
|
|
|
|
2015-12-15 21:53:15 +00:00
|
|
|
updateContentOpacity(0.0);
|
|
|
|
}
|
|
|
|
|
2015-12-30 22:04:58 +00:00
|
|
|
void FileBrowser::navigateToPath(const HECL::SystemString& path)
|
|
|
|
{
|
|
|
|
HECL::Sstat theStat;
|
|
|
|
if (HECL::Stat(path.c_str(), &theStat))
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_comps = PathComponents(path);
|
|
|
|
if (S_ISREG(theStat.st_mode))
|
|
|
|
{
|
|
|
|
HECL::SystemUTF8View utf8(m_comps.back());
|
|
|
|
m_fileField.m_view->setText(utf8);
|
|
|
|
m_comps.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
HECL::SystemString dir;
|
|
|
|
bool needSlash = false;
|
|
|
|
for (const HECL::SystemString& d : m_comps)
|
|
|
|
{
|
|
|
|
if (needSlash)
|
|
|
|
dir += '/';
|
|
|
|
needSlash = true;
|
|
|
|
dir += d;
|
|
|
|
}
|
|
|
|
HECL::DirectoryEnumerator dEnum(dir);
|
|
|
|
m_fileListingBind.updateListing(dEnum);
|
|
|
|
m_fileListing.m_view->updateData();
|
|
|
|
|
|
|
|
m_pathButtons.clear();
|
|
|
|
m_pathButtons.reserve(m_comps.size());
|
|
|
|
size_t idx = 0;
|
|
|
|
ViewResources& res = rootView().viewRes();
|
|
|
|
for (const HECL::SystemString& c : m_comps)
|
|
|
|
m_pathButtons.emplace_back(*this, res, idx++, c);
|
|
|
|
|
|
|
|
updateSize();
|
|
|
|
}
|
|
|
|
|
2015-12-15 21:53:15 +00:00
|
|
|
void FileBrowser::updateContentOpacity(float opacity)
|
|
|
|
{
|
|
|
|
Zeus::CColor color = Zeus::CColor::lerp({1,1,1,0}, {1,1,1,1}, opacity);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_split.m_view->setMultiplyColor(color);
|
2015-12-15 21:53:15 +00:00
|
|
|
for (PathButton& b : m_pathButtons)
|
|
|
|
b.m_button.m_view->setMultiplyColor(color);
|
2015-12-17 21:28:37 +00:00
|
|
|
m_fileField.m_view->setMultiplyColor(color);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fileListing.m_view->setMultiplyColor(color);
|
|
|
|
m_ok.m_button.m_view->setMultiplyColor(color);
|
|
|
|
m_cancel.m_button.m_view->setMultiplyColor(color);
|
2015-12-30 22:04:58 +00:00
|
|
|
m_systemBookmarks.m_view->setMultiplyColor(color);
|
|
|
|
m_systemBookmarksLabel->setMultiplyColor(color);
|
|
|
|
m_projectBookmarks.m_view->setMultiplyColor(color);
|
|
|
|
m_projectBookmarksLabel->setMultiplyColor(color);
|
|
|
|
m_recentBookmarks.m_view->setMultiplyColor(color);
|
|
|
|
m_recentBookmarksLabel->setMultiplyColor(color);
|
2015-12-22 01:33:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::okActivated()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::cancelActivated()
|
|
|
|
{
|
2015-12-23 00:25:46 +00:00
|
|
|
close();
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::pathButtonActivated(size_t idx)
|
|
|
|
{
|
2015-12-30 22:04:58 +00:00
|
|
|
if (idx >= m_comps.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
HECL::SystemString dir;
|
|
|
|
bool needSlash = false;
|
|
|
|
size_t i = 0;
|
|
|
|
for (const HECL::SystemString& d : m_comps)
|
|
|
|
{
|
|
|
|
if (needSlash)
|
|
|
|
dir += '/';
|
|
|
|
needSlash = true;
|
|
|
|
dir += d;
|
|
|
|
if (++i > idx)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
navigateToPath(dir);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
|
|
|
{
|
2015-12-23 00:25:46 +00:00
|
|
|
if (skipBuildInAnimation() || closed())
|
2015-12-15 21:53:15 +00:00
|
|
|
return;
|
2015-12-22 01:33:27 +00:00
|
|
|
m_split.mouseDown(coord, button, mod);
|
2015-12-15 21:53:15 +00:00
|
|
|
for (PathButton& b : m_pathButtons)
|
|
|
|
b.m_button.mouseDown(coord, button, mod);
|
2015-12-17 21:28:37 +00:00
|
|
|
m_fileField.mouseDown(coord, button, mod);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fileListing.mouseDown(coord, button, mod);
|
|
|
|
m_ok.m_button.mouseDown(coord, button, mod);
|
|
|
|
m_cancel.m_button.mouseDown(coord, button, mod);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
|
|
|
{
|
2015-12-23 00:25:46 +00:00
|
|
|
if (closed())
|
|
|
|
return;
|
2015-12-30 22:04:58 +00:00
|
|
|
|
2015-12-22 01:33:27 +00:00
|
|
|
m_split.mouseUp(coord, button, mod);
|
2015-12-30 22:04:58 +00:00
|
|
|
|
2015-12-15 21:53:15 +00:00
|
|
|
for (PathButton& b : m_pathButtons)
|
|
|
|
b.m_button.mouseUp(coord, button, mod);
|
2015-12-30 22:04:58 +00:00
|
|
|
if (m_pathButtonPending >= 0)
|
|
|
|
{
|
|
|
|
pathButtonActivated(m_pathButtonPending);
|
|
|
|
m_pathButtonPending = -1;
|
|
|
|
}
|
|
|
|
|
2015-12-17 21:28:37 +00:00
|
|
|
m_fileField.mouseUp(coord, button, mod);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fileListing.mouseUp(coord, button, mod);
|
|
|
|
m_ok.m_button.mouseUp(coord, button, mod);
|
|
|
|
m_cancel.m_button.mouseUp(coord, button, mod);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::mouseMove(const boo::SWindowCoord& coord)
|
|
|
|
{
|
2015-12-23 00:25:46 +00:00
|
|
|
if (closed())
|
|
|
|
return;
|
2015-12-22 01:33:27 +00:00
|
|
|
m_split.mouseMove(coord);
|
2015-12-15 21:53:15 +00:00
|
|
|
for (PathButton& b : m_pathButtons)
|
|
|
|
b.m_button.mouseMove(coord);
|
2015-12-17 21:28:37 +00:00
|
|
|
m_fileField.mouseMove(coord);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fileListing.mouseMove(coord);
|
|
|
|
m_ok.m_button.mouseMove(coord);
|
|
|
|
m_cancel.m_button.mouseMove(coord);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::mouseEnter(const boo::SWindowCoord& coord)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::mouseLeave(const boo::SWindowCoord& coord)
|
|
|
|
{
|
2015-12-23 00:25:46 +00:00
|
|
|
if (closed())
|
|
|
|
return;
|
2015-12-22 01:33:27 +00:00
|
|
|
m_split.mouseLeave(coord);
|
2015-12-15 21:53:15 +00:00
|
|
|
for (PathButton& b : m_pathButtons)
|
|
|
|
b.m_button.mouseLeave(coord);
|
2015-12-17 21:28:37 +00:00
|
|
|
m_fileField.mouseLeave(coord);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fileListing.mouseLeave(coord);
|
|
|
|
m_ok.m_button.mouseLeave(coord);
|
|
|
|
m_cancel.m_button.mouseLeave(coord);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
2015-12-20 04:39:09 +00:00
|
|
|
void FileBrowser::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll)
|
|
|
|
{
|
2015-12-29 02:02:43 +00:00
|
|
|
m_fileListing.scroll(coord, scroll);
|
2015-12-20 04:39:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::touchDown(const boo::STouchCoord& coord, uintptr_t tid)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::touchUp(const boo::STouchCoord& coord, uintptr_t tid)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::touchMove(const boo::STouchCoord& coord, uintptr_t tid)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-12-15 21:53:15 +00:00
|
|
|
void FileBrowser::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
|
|
|
{
|
|
|
|
ModalWindow::resized(root, root);
|
|
|
|
float pf = rootView().viewRes().pixelFactor();
|
|
|
|
|
2015-12-20 04:39:09 +00:00
|
|
|
boo::SWindowRect centerRect = subRect();
|
2015-12-22 01:33:27 +00:00
|
|
|
centerRect.location[0] = root.size[0] / 2 - (centerRect.size[0] / 2.0) + 2 * pf;
|
2015-12-30 02:20:24 +00:00
|
|
|
centerRect.location[1] = root.size[1] / 2 - (centerRect.size[1] / 2.0) + 2 * pf;
|
2015-12-22 01:33:27 +00:00
|
|
|
centerRect.size[0] -= 4 * pf;
|
|
|
|
centerRect.size[1] -= 4 * pf;
|
|
|
|
|
2015-12-30 22:04:58 +00:00
|
|
|
if (m_split.m_view)
|
|
|
|
m_split.m_view->resized(root, centerRect);
|
2015-12-22 01:33:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::LeftSide::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
|
|
|
{
|
2015-12-30 22:04:58 +00:00
|
|
|
float pf = rootView().viewRes().pixelFactor();
|
|
|
|
|
|
|
|
int div = (sub.size[1] - BROWSER_MARGIN * pf) / 3;
|
|
|
|
|
|
|
|
boo::SWindowRect bookmarkRect = sub;
|
|
|
|
bookmarkRect.size[0] -= BROWSER_MARGIN * 2 * pf;
|
|
|
|
bookmarkRect.size[1] = div;
|
|
|
|
bookmarkRect.location[0] += BROWSER_MARGIN * pf;
|
|
|
|
bookmarkRect.location[1] = sub.location[1] + BROWSER_MARGIN * pf + div * 2;
|
|
|
|
|
|
|
|
boo::SWindowRect labelRect = bookmarkRect;
|
|
|
|
labelRect.size[1] = 20;
|
|
|
|
labelRect.location[1] += div - 16 * pf;
|
|
|
|
|
|
|
|
m_fb.m_systemBookmarks.m_view->resized(root, bookmarkRect);
|
|
|
|
m_fb.m_systemBookmarksLabel->resized(root, labelRect);
|
|
|
|
bookmarkRect.location[1] -= div;
|
|
|
|
labelRect.location[1] -= div;
|
|
|
|
|
|
|
|
m_fb.m_projectBookmarks.m_view->resized(root, bookmarkRect);
|
|
|
|
m_fb.m_projectBookmarksLabel->resized(root, labelRect);
|
|
|
|
bookmarkRect.location[1] -= div;
|
|
|
|
labelRect.location[1] -= div;
|
|
|
|
|
|
|
|
m_fb.m_recentBookmarks.m_view->resized(root, bookmarkRect);
|
|
|
|
m_fb.m_recentBookmarksLabel->resized(root, labelRect);
|
|
|
|
|
2015-12-22 01:33:27 +00:00
|
|
|
}
|
2015-12-15 21:53:15 +00:00
|
|
|
|
2015-12-22 01:33:27 +00:00
|
|
|
void FileBrowser::RightSide::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
|
|
|
{
|
|
|
|
float pf = rootView().viewRes().pixelFactor();
|
|
|
|
|
|
|
|
boo::SWindowRect pathRect = sub;
|
2015-12-30 02:50:56 +00:00
|
|
|
pathRect.location[0] += BROWSER_MARGIN * pf;
|
|
|
|
pathRect.location[1] += pathRect.size[1] - (BROWSER_MARGIN + 20) * pf;
|
2015-12-22 01:33:27 +00:00
|
|
|
for (PathButton& b : m_fb.m_pathButtons)
|
2015-12-15 21:53:15 +00:00
|
|
|
{
|
|
|
|
pathRect.size[0] = b.m_button.m_view->nominalWidth();
|
|
|
|
pathRect.size[1] = b.m_button.m_view->nominalHeight();
|
|
|
|
b.m_button.m_view->resized(root, pathRect);
|
2015-12-18 03:26:10 +00:00
|
|
|
pathRect.location[0] += pathRect.size[0] + 2;
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
2015-12-17 21:28:37 +00:00
|
|
|
|
2015-12-30 02:50:56 +00:00
|
|
|
pathRect.location[0] = sub.location[0] + BROWSER_MARGIN * pf;
|
2015-12-17 21:28:37 +00:00
|
|
|
pathRect.location[1] -= 25 * pf;
|
2015-12-30 02:50:56 +00:00
|
|
|
pathRect.size[0] = sub.size[0] - m_fb.m_ok.m_button.m_view->nominalWidth() - 20 * pf;
|
2015-12-22 01:33:27 +00:00
|
|
|
pathRect.size[1] = m_fb.m_fileField.m_view->nominalHeight();
|
|
|
|
m_fb.m_fileField.m_view->resized(root, pathRect);
|
|
|
|
|
2015-12-30 02:50:56 +00:00
|
|
|
pathRect.location[1] = sub.location[1] + BROWSER_MARGIN * pf;
|
|
|
|
pathRect.size[0] = sub.size[0] - BROWSER_MARGIN * 2 * pf;
|
|
|
|
pathRect.size[1] = sub.size[1] - (BROWSER_MARGIN + 56) * pf;
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fb.m_fileListing.m_view->resized(root, pathRect);
|
|
|
|
|
|
|
|
boo::SWindowRect buttonRect = sub;
|
|
|
|
buttonRect.size[0] = m_fb.m_ok.m_button.m_view->nominalWidth();
|
|
|
|
buttonRect.size[1] = m_fb.m_ok.m_button.m_view->nominalHeight();
|
2015-12-30 02:50:56 +00:00
|
|
|
buttonRect.location[0] += sub.size[0] - BROWSER_MARGIN * pf - buttonRect.size[0];
|
|
|
|
buttonRect.location[1] += sub.size[1] - (BROWSER_MARGIN + 20) * pf;
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fb.m_ok.m_button.m_view->resized(root, buttonRect);
|
|
|
|
buttonRect.location[1] -= 25 * pf;
|
|
|
|
m_fb.m_cancel.m_button.m_view->resized(root, buttonRect);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
2015-12-20 04:39:09 +00:00
|
|
|
void FileBrowser::think()
|
|
|
|
{
|
|
|
|
ModalWindow::think();
|
|
|
|
m_fileField.m_view->think();
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fileListing.m_view->think();
|
2015-12-30 22:04:58 +00:00
|
|
|
m_systemBookmarks.m_view->think();
|
|
|
|
m_projectBookmarks.m_view->think();
|
|
|
|
m_recentBookmarks.m_view->think();
|
2015-12-20 04:39:09 +00:00
|
|
|
}
|
|
|
|
|
2015-12-15 21:53:15 +00:00
|
|
|
void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ)
|
|
|
|
{
|
|
|
|
ModalWindow::draw(gfxQ);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_split.m_view->draw(gfxQ);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::LeftSide::draw(boo::IGraphicsCommandQueue* gfxQ)
|
|
|
|
{
|
2015-12-30 22:04:58 +00:00
|
|
|
m_fb.m_systemBookmarks.m_view->draw(gfxQ);
|
|
|
|
m_fb.m_systemBookmarksLabel->draw(gfxQ);
|
|
|
|
m_fb.m_projectBookmarks.m_view->draw(gfxQ);
|
|
|
|
m_fb.m_projectBookmarksLabel->draw(gfxQ);
|
|
|
|
m_fb.m_recentBookmarks.m_view->draw(gfxQ);
|
|
|
|
m_fb.m_recentBookmarksLabel->draw(gfxQ);
|
2015-12-22 01:33:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FileBrowser::RightSide::draw(boo::IGraphicsCommandQueue* gfxQ)
|
|
|
|
{
|
|
|
|
for (PathButton& b : m_fb.m_pathButtons)
|
2015-12-15 21:53:15 +00:00
|
|
|
b.m_button.m_view->draw(gfxQ);
|
2015-12-22 01:33:27 +00:00
|
|
|
m_fb.m_fileField.m_view->draw(gfxQ);
|
|
|
|
m_fb.m_fileListing.m_view->draw(gfxQ);
|
|
|
|
m_fb.m_ok.m_button.m_view->draw(gfxQ);
|
|
|
|
m_fb.m_cancel.m_button.m_view->draw(gfxQ);
|
2015-12-15 21:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|