Add MessageWindow class

This commit is contained in:
Jack Andersen 2016-01-02 13:07:40 -10:00
parent 26dffbd99e
commit 8dfafc81c2
11 changed files with 277 additions and 3 deletions

View File

@ -37,6 +37,7 @@ list(APPEND SPECTER_HEADERS
include/Specter/View.hpp include/Specter/View.hpp
include/Specter/RootView.hpp include/Specter/RootView.hpp
include/Specter/ModalWindow.hpp include/Specter/ModalWindow.hpp
include/Specter/MessageWindow.hpp
include/Specter/Tooltip.hpp include/Specter/Tooltip.hpp
include/Specter/SplitView.hpp include/Specter/SplitView.hpp
include/Specter/ScrollView.hpp include/Specter/ScrollView.hpp
@ -66,6 +67,7 @@ list(APPEND SPECTER_SOURCES
lib/View.cpp lib/View.cpp
lib/RootView.cpp lib/RootView.cpp
lib/ModalWindow.cpp lib/ModalWindow.cpp
lib/MessageWindow.cpp
lib/Tooltip.cpp lib/Tooltip.cpp
lib/SplitView.cpp lib/SplitView.cpp
lib/ScrollView.cpp lib/ScrollView.cpp

View File

@ -9,6 +9,7 @@
#include "Table.hpp" #include "Table.hpp"
#include "ViewResources.hpp" #include "ViewResources.hpp"
#include "IViewManager.hpp" #include "IViewManager.hpp"
#include "MessageWindow.hpp"
#include <HECL/HECL.hpp> #include <HECL/HECL.hpp>
namespace Specter namespace Specter
@ -20,6 +21,7 @@ public:
enum class Type enum class Type
{ {
SaveFile, SaveFile,
SaveDirectory,
OpenFile, OpenFile,
OpenDirectory, OpenDirectory,
OpenHECLProject OpenHECLProject
@ -114,6 +116,8 @@ private:
} }
} m_fileFieldBind; } m_fileFieldBind;
std::unique_ptr<MessageWindow> m_confirmWindow;
struct FileListingDataBind : ITableDataBinding, ITableStateBinding struct FileListingDataBind : ITableDataBinding, ITableStateBinding
{ {
FileBrowser& m_fb; FileBrowser& m_fb;

View File

@ -0,0 +1,78 @@
#ifndef SPECTER_MESSAGEWINDOW_HPP
#define SPECTER_MESSAGEWINDOW_HPP
#include "ModalWindow.hpp"
#include "MultiLineTextView.hpp"
#include "Button.hpp"
namespace Specter
{
class MessageWindow : public ModalWindow
{
public:
enum class Type
{
InfoOk,
ErrorOk,
ConfirmOkCancel
};
private:
Type m_type;
std::function<void(bool ok)> m_func;
std::unique_ptr<MultiLineTextView> m_text;
struct OKBinding : IButtonBinding
{
MessageWindow& m_mw;
std::string m_name;
OKBinding(MessageWindow& mw, std::string&& name) : m_mw(mw), m_name(std::move(name)) {}
const char* name() const {return m_name.c_str();}
void activated(const boo::SWindowCoord& coord)
{
m_mw.m_func(true);
}
} m_okBind;
ViewChild<std::unique_ptr<Button>> m_ok;
struct CancelBinding : IButtonBinding
{
MessageWindow& m_mw;
std::string m_name;
CancelBinding(MessageWindow& mw, std::string&& name) : m_mw(mw), m_name(std::move(name)) {}
const char* name() const {return m_name.c_str();}
void activated(const boo::SWindowCoord& coord)
{
m_mw.m_func(false);
}
} m_cancelBind;
ViewChild<std::unique_ptr<Button>> m_cancel;
public:
MessageWindow(ViewResources& res, View& parentView,
Type type, const std::string& message, std::function<void(bool ok)> func);
void updateContentOpacity(float opacity)
{
Zeus::CColor color = Zeus::CColor::lerp({1,1,1,0}, {1,1,1,1}, opacity);
ModalWindow::setMultiplyColor(color);
m_text->setMultiplyColor(color);
m_ok.m_view->setMultiplyColor(color);
m_cancel.m_view->setMultiplyColor(color);
}
void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
void mouseMove(const boo::SWindowCoord&);
void mouseEnter(const boo::SWindowCoord&);
void mouseLeave(const boo::SWindowCoord&);
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
void draw(boo::IGraphicsCommandQueue* gfxQ);
};
}
#endif // SPECTER_MESSAGEWINDOW_HPP

View File

@ -59,6 +59,7 @@ protected:
virtual void updateContentOpacity(float opacity) {} virtual void updateContentOpacity(float opacity) {}
public: public:
ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint, const Zeus::CColor& bgColor);
ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint); ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint);
void think(); void think();
bool skipBuildInAnimation(); bool skipBuildInAnimation();

View File

@ -37,6 +37,12 @@ public:
void colorGlyphs(const Zeus::CColor& newColor); void colorGlyphs(const Zeus::CColor& newColor);
void setMultiplyColor(const Zeus::CColor& color)
{
for (std::unique_ptr<TextView>& l : m_lines)
l->setMultiplyColor(color);
}
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
void draw(boo::IGraphicsCommandQueue* gfxQ); void draw(boo::IGraphicsCommandQueue* gfxQ);

View File

@ -21,6 +21,7 @@ class ThemeData
Zeus::CColor m_tbBg = {0.4, 0.4, 0.4, 1.0}; Zeus::CColor m_tbBg = {0.4, 0.4, 0.4, 1.0};
Zeus::CColor m_tooltipBg = {0.1, 0.1, 0.1, 0.85}; Zeus::CColor m_tooltipBg = {0.1, 0.1, 0.1, 0.85};
Zeus::CColor m_splashBg = {0.075, 0.075, 0.075, 0.85}; Zeus::CColor m_splashBg = {0.075, 0.075, 0.075, 0.85};
Zeus::CColor m_splashErrorBg = {0.1, 0.01, 0.01, 0.85};
Zeus::CColor m_splash1 = {1.0, 1.0, 1.0, 1.0}; Zeus::CColor m_splash1 = {1.0, 1.0, 1.0, 1.0};
Zeus::CColor m_splash2 = {0.3, 0.3, 0.3, 1.0}; Zeus::CColor m_splash2 = {0.3, 0.3, 0.3, 1.0};
@ -59,6 +60,7 @@ public:
virtual const Zeus::CColor& toolbarBackground() const {return m_tbBg;} virtual const Zeus::CColor& toolbarBackground() const {return m_tbBg;}
virtual const Zeus::CColor& tooltipBackground() const {return m_tooltipBg;} virtual const Zeus::CColor& tooltipBackground() const {return m_tooltipBg;}
virtual const Zeus::CColor& splashBackground() const {return m_splashBg;} virtual const Zeus::CColor& splashBackground() const {return m_splashBg;}
virtual const Zeus::CColor& splashErrorBackground() const {return m_splashErrorBg;}
virtual const Zeus::CColor& splash1() const {return m_splash1;} virtual const Zeus::CColor& splash1() const {return m_splash1;}
virtual const Zeus::CColor& splash2() const {return m_splash2;} virtual const Zeus::CColor& splash2() const {return m_splash2;}

View File

@ -275,7 +275,7 @@ void Button::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
float pf = rootView().viewRes().pixelFactor(); float pf = rootView().viewRes().pixelFactor();
if (m_style == Style::Block) if (m_style == Style::Block)
textRect.location[1] += 7 * pf; textRect.location[1] += 7 * pf;
textRect.location[0] += sub.size[0] / 2; textRect.location[0] += m_nomWidth / 2;
textRect.size[0] = m_nomWidth; textRect.size[0] = m_nomWidth;
textRect.size[1] = m_nomHeight; textRect.size[1] = m_nomHeight;
m_text->resized(root, textRect); m_text->resized(root, textRect);

View File

@ -1,5 +1,6 @@
#include "Specter/FileBrowser.hpp" #include "Specter/FileBrowser.hpp"
#include "Specter/RootView.hpp" #include "Specter/RootView.hpp"
#include "Specter/MessageWindow.hpp"
namespace Specter namespace Specter
{ {
@ -207,6 +208,54 @@ void FileBrowser::okActivated(bool viaButton)
int err = HECL::Stat(path.c_str(), &theStat); int err = HECL::Stat(path.c_str(), &theStat);
if (m_type == Type::SaveFile) if (m_type == Type::SaveFile)
{ {
if (m_fileField.m_view->getText().empty())
{
m_fileField.m_view->setErrorState(
vm.translateOr("file_field_empty", "Unable to save empty file").c_str());
return;
}
if (!err && !S_ISDIR(theStat.st_mode))
{
m_confirmWindow.reset(new MessageWindow(rootView().viewRes(), *this,
MessageWindow::Type::ConfirmOkCancel,
HECL::Format(vm.translateOr("overwrite_confirm", "Overwrite '%s'?").c_str(), path.c_str()),
[&,path](bool ok)
{
if (ok)
{
m_returnFunc(true, path);
m_confirmWindow->close();
close();
}
else
m_confirmWindow->close();
}));
updateSize();
return;
}
if (!err && S_ISDIR(theStat.st_mode))
{
navigateToPath(path);
return;
}
m_returnFunc(true, path);
close();
return;
}
else if (m_type == Type::SaveDirectory)
{
if (m_fileField.m_view->getText().empty())
{
m_fileField.m_view->setErrorState(
vm.translateOr("directory_field_empty", "Unable to make empty-named directory").c_str());
return;
}
if (!err && !S_ISDIR(theStat.st_mode))
{
m_fileField.m_view->setErrorState(
vm.translateOr("no_overwrite_file", "Unable to make directory over file").c_str());
return;
}
if (!err && S_ISDIR(theStat.st_mode)) if (!err && S_ISDIR(theStat.st_mode))
{ {
navigateToPath(path); navigateToPath(path);
@ -302,6 +351,10 @@ void FileBrowser::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton bu
{ {
if (skipBuildInAnimation() || closed()) if (skipBuildInAnimation() || closed())
return; return;
if (m_confirmWindow)
m_confirmWindow->mouseDown(coord, button, mod);
m_split.mouseDown(coord, button, mod); m_split.mouseDown(coord, button, mod);
for (PathButton& b : m_pathButtons) for (PathButton& b : m_pathButtons)
b.m_button.mouseDown(coord, button, mod); b.m_button.mouseDown(coord, button, mod);
@ -336,6 +389,9 @@ void FileBrowser::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton butt
m_recentBookmarks.m_view->mouseUp(coord, button, mod); m_recentBookmarks.m_view->mouseUp(coord, button, mod);
m_ok.m_button.mouseUp(coord, button, mod); m_ok.m_button.mouseUp(coord, button, mod);
m_cancel.m_button.mouseUp(coord, button, mod); m_cancel.m_button.mouseUp(coord, button, mod);
if (m_confirmWindow)
m_confirmWindow->mouseUp(coord, button, mod);
} }
void FileBrowser::mouseMove(const boo::SWindowCoord& coord) void FileBrowser::mouseMove(const boo::SWindowCoord& coord)
@ -352,6 +408,9 @@ void FileBrowser::mouseMove(const boo::SWindowCoord& coord)
m_recentBookmarks.m_view->mouseMove(coord); m_recentBookmarks.m_view->mouseMove(coord);
m_ok.m_button.mouseMove(coord); m_ok.m_button.mouseMove(coord);
m_cancel.m_button.mouseMove(coord); m_cancel.m_button.mouseMove(coord);
if (m_confirmWindow)
m_confirmWindow->mouseMove(coord);
} }
void FileBrowser::mouseEnter(const boo::SWindowCoord& coord) void FileBrowser::mouseEnter(const boo::SWindowCoord& coord)
@ -369,6 +428,9 @@ void FileBrowser::mouseLeave(const boo::SWindowCoord& coord)
m_fileListing.mouseLeave(coord); m_fileListing.mouseLeave(coord);
m_ok.m_button.mouseLeave(coord); m_ok.m_button.mouseLeave(coord);
m_cancel.m_button.mouseLeave(coord); m_cancel.m_button.mouseLeave(coord);
if (m_confirmWindow)
m_confirmWindow->mouseLeave(coord);
} }
void FileBrowser::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) void FileBrowser::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll)
@ -422,6 +484,9 @@ void FileBrowser::resized(const boo::SWindowRect& root, const boo::SWindowRect&
if (m_split.m_view) if (m_split.m_view)
m_split.m_view->resized(root, centerRect); m_split.m_view->resized(root, centerRect);
if (m_confirmWindow)
m_confirmWindow->resized(root, sub);
} }
void FileBrowser::LeftSide::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) void FileBrowser::LeftSide::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
@ -500,12 +565,18 @@ void FileBrowser::think()
m_systemBookmarks.m_view->think(); m_systemBookmarks.m_view->think();
m_projectBookmarks.m_view->think(); m_projectBookmarks.m_view->think();
m_recentBookmarks.m_view->think(); m_recentBookmarks.m_view->think();
if (m_confirmWindow)
m_confirmWindow->think();
} }
void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ) void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ)
{ {
ModalWindow::draw(gfxQ); ModalWindow::draw(gfxQ);
m_split.m_view->draw(gfxQ); m_split.m_view->draw(gfxQ);
if (m_confirmWindow)
m_confirmWindow->draw(gfxQ);
} }
void FileBrowser::LeftSide::draw(boo::IGraphicsCommandQueue* gfxQ) void FileBrowser::LeftSide::draw(boo::IGraphicsCommandQueue* gfxQ)

View File

@ -0,0 +1,107 @@
#include "Specter/MessageWindow.hpp"
#include "Specter/ViewResources.hpp"
#include "Specter/RootView.hpp"
namespace Specter
{
MessageWindow::MessageWindow(ViewResources& res, View& parentView,
Type type, const std::string& message,
std::function<void (bool)> func)
: ModalWindow(res, parentView, RectangleConstraint(400 * res.pixelFactor(), 150 * res.pixelFactor()),
type==Type::ErrorOk ? res.themeData().splashErrorBackground() : res.themeData().splashBackground()),
m_type(type), m_func(func),
m_okBind(*this, rootView().viewManager().translateOr("ok", "OK")),
m_cancelBind(*this, rootView().viewManager().translateOr("cancel", "Cancel"))
{
commitResources(res);
m_text.reset(new MultiLineTextView(res, *this, res.m_mainFont, TextView::Alignment::Center));
m_text->typesetGlyphs(message, res.themeData().uiText(), 380 * res.pixelFactor());
m_ok.m_view.reset(new Button(res, *this, &m_okBind, m_okBind.m_name,
Button::Style::Block, RectangleConstraint(150 * res.pixelFactor())));
if (type == Type::ConfirmOkCancel)
m_cancel.m_view.reset(new Button(res, *this, &m_cancelBind, m_cancelBind.m_name,
Button::Style::Block, RectangleConstraint(150 * res.pixelFactor())));
updateContentOpacity(0.0);
}
void MessageWindow::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods)
{
if (closed() || skipBuildInAnimation())
return;
m_ok.mouseDown(coord, button, mods);
m_cancel.mouseDown(coord, button, mods);
}
void MessageWindow::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mods)
{
if (closed())
return;
m_ok.mouseUp(coord, button, mods);
m_cancel.mouseUp(coord, button, mods);
}
void MessageWindow::mouseMove(const boo::SWindowCoord& coord)
{
if (closed())
return;
m_ok.mouseMove(coord);
m_cancel.mouseMove(coord);
}
void MessageWindow::mouseEnter(const boo::SWindowCoord& coord)
{
if (closed())
return;
m_ok.mouseEnter(coord);
m_cancel.mouseEnter(coord);
}
void MessageWindow::mouseLeave(const boo::SWindowCoord& coord)
{
if (closed())
return;
m_ok.mouseLeave(coord);
m_cancel.mouseLeave(coord);
}
void MessageWindow::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
{
ModalWindow::resized(root, sub);
boo::SWindowRect buttonRect = subRect();
float pf = rootView().viewRes().pixelFactor();
buttonRect.location[1] += 25 * pf;
buttonRect.size[0] = m_ok.m_view->nominalWidth();
buttonRect.size[1] = m_ok.m_view->nominalHeight();
if (m_type == Type::ConfirmOkCancel)
{
buttonRect.location[0] += 45 * pf;
m_ok.m_view->resized(root, buttonRect);
buttonRect.location[0] += 160 * pf;
m_cancel.m_view->resized(root, buttonRect);
}
else
{
buttonRect.location[0] += 125 * pf;
m_ok.m_view->resized(root, buttonRect);
}
boo::SWindowRect textRect = subRect();
textRect.location[0] += 200 * pf;
textRect.location[1] += 120 * pf;
m_text->resized(root, textRect);
}
void MessageWindow::draw(boo::IGraphicsCommandQueue* gfxQ)
{
ModalWindow::draw(gfxQ);
m_text->draw(gfxQ);
m_ok.m_view->draw(gfxQ);
if (m_type == Type::ConfirmOkCancel)
m_cancel.m_view->draw(gfxQ);
}
}

View File

@ -276,9 +276,12 @@ void ModalWindow::setFillColors(float t)
} }
ModalWindow::ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint) ModalWindow::ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint)
: ModalWindow(res, parentView, constraint, res.themeData().splashBackground()) {}
ModalWindow::ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint, const Zeus::CColor& bgColor)
: View(res, parentView), : View(res, parentView),
m_constraint(constraint), m_constraint(constraint),
m_windowBg(res.themeData().splashBackground()), m_windowBg(bgColor),
m_windowBgClear(m_windowBg), m_windowBgClear(m_windowBg),
m_line1(res.themeData().splash1()), m_line1(res.themeData().splash1()),
m_line2(res.themeData().splash2()), m_line2(res.themeData().splash2()),

View File

@ -58,7 +58,7 @@ std::string MultiLineTextView::LineWrap(const std::string& str, int wrap)
continue; continue;
} }
if (sz == 1 && (it[0] == ' ' || it[0] == '-')) if (sz == 1 && (it[0] == ' ' || it[0] == '-' || it[0] == '/' || it[0] == '\\'))
{ {
lastSpaceIt = it + 1; lastSpaceIt = it + 1;
lastSpaceRem = rem - 1; lastSpaceRem = rem - 1;