Show a tooltip with author+link of each palette (fix #540)

This commit is contained in:
David Capello 2016-09-15 15:30:45 -03:00
parent 64f2384bfc
commit 2e3bbe2968
7 changed files with 194 additions and 86 deletions

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -13,23 +13,99 @@
#include "app/modules/palettes.h"
#include "app/res/palette_resource.h"
#include "app/res/palettes_loader_delegate.h"
#include "app/ui/icon_button.h"
#include "app/ui/skin/skin_theme.h"
#include "base/bind.h"
#include "base/launcher.h"
#include "doc/palette.h"
#include "she/surface.h"
#include "ui/graphics.h"
#include "ui/listitem.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/resize_event.h"
#include "ui/size_hint_event.h"
#include "ui/tooltips.h"
#include "ui/view.h"
namespace app {
using namespace ui;
using namespace app::skin;
static bool is_url_char(int chr)
{
return ((chr >= 'a' && chr <= 'z') ||
(chr >= 'A' && chr <= 'Z') ||
(chr >= '0' && chr <= '9') ||
(chr == ':' || chr == '/' || chr == '@' ||
chr == '?' || chr == '!' || chr == '#' ||
chr == '-' || chr == '_' || chr == '~' ||
chr == '.' || chr == ',' || chr == ';' ||
chr == '*' || chr == '+' || chr == '=' ||
chr == '[' || chr == ']' ||
chr == '(' || chr == ')' ||
chr == '$' || chr == '\''));
}
class PalettesListItem : public ResourceListItem {
class CommentButton : public IconButton {
public:
CommentButton(const std::string& comment)
: IconButton(SkinTheme::instance()->parts.iconUserData()->bitmap(0))
, m_comment(comment) {
}
private:
void onClick(Event& ev) override {
IconButton::onClick(ev);
int j, i = m_comment.find("http");
if (i != std::string::npos) {
for (j=i+4; j<m_comment.size() && is_url_char(m_comment[j]); ++j)
;
base::launcher::open_url(m_comment.substr(i, j-i));
}
}
std::string m_comment;
};
public:
PalettesListItem(Resource* resource, TooltipManager* tooltips)
: ResourceListItem(resource)
, m_comment(nullptr)
{
std::string comment = static_cast<PaletteResource*>(resource)->palette()->comment();
if (!comment.empty()) {
addChild(m_comment = new CommentButton(comment));
m_comment->setBgColor(SkinTheme::instance()->colors.listitemNormalFace());
tooltips->addTooltipFor(m_comment, comment, LEFT);
}
}
private:
void onResize(ResizeEvent& ev) override {
ResourceListItem::onResize(ev);
if (m_comment) {
auto reqSz = m_comment->sizeHint();
m_comment->setBounds(
gfx::Rect(ev.bounds().x+ev.bounds().w-reqSz.w,
ev.bounds().y+ev.bounds().h/2-reqSz.h/2,
reqSz.w, reqSz.h));
}
}
CommentButton* m_comment;
};
PalettesListBox::PalettesListBox()
: ResourcesListBox(new ResourcesLoader(new PalettesLoaderDelegate))
{
addChild(&m_tooltips);
}
doc::Palette* PalettesListBox::selectedPalette()
@ -41,10 +117,13 @@ doc::Palette* PalettesListBox::selectedPalette()
return static_cast<PaletteResource*>(resource)->palette();
}
ResourceListItem* PalettesListBox::onCreateResourceItem(Resource* resource)
{
return new PalettesListItem(resource, &m_tooltips);
}
void PalettesListBox::onResourceChange(Resource* resource)
{
ResourcesListBox::onResourceChange(resource);
doc::Palette* palette = static_cast<PaletteResource*>(resource)->palette();
PalChange(palette);
}
@ -67,11 +146,6 @@ void PalettesListBox::onPaintResource(Graphics* g, const gfx::Rect& bounds, Reso
box.x += box.w;
}
// g->drawString(getText(), fgcolor, gfx::ColorNone, false,
// gfx::Point(
// bounds.x + guiscale()*2,
// bounds.y + bounds.h/2 - g->measureUIString(getText()).h/2));
}
void PalettesListBox::onResourceSizeHint(Resource* resource, gfx::Size& size)

View File

@ -9,6 +9,7 @@
#pragma once
#include "app/ui/resources_listbox.h"
#include "ui/tooltips.h"
namespace doc {
class Palette;
@ -25,9 +26,12 @@ namespace app {
obs::signal<void(doc::Palette*)> PalChange;
protected:
virtual ResourceListItem* onCreateResourceItem(Resource* resource) override;
virtual void onResourceChange(Resource* resource) override;
virtual void onPaintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource) override;
virtual void onResourceSizeHint(Resource* resource, gfx::Size& size) override;
ui::TooltipManager m_tooltips;
};
} // namespace app

View File

@ -15,7 +15,6 @@
#include "app/ui/skin/skin_theme.h"
#include "base/bind.h"
#include "ui/graphics.h"
#include "ui/listitem.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/size_hint_event.h"
@ -26,73 +25,61 @@ namespace app {
using namespace ui;
using namespace skin;
class ResourceListItem : public ListItem {
public:
ResourceListItem(Resource* resource)
: ListItem(resource->name()), m_resource(resource) {
//////////////////////////////////////////////////////////////////////
// ResourceListItem
ResourceListItem::ResourceListItem(Resource* resource)
: ListItem(resource->name()), m_resource(resource)
{
}
bool ResourceListItem::onProcessMessage(ui::Message* msg)
{
switch (msg->type()) {
case kMouseLeaveMessage:
case kMouseEnterMessage:
invalidate();
break;
}
return ListItem::onProcessMessage(msg);
}
void ResourceListItem::onPaint(PaintEvent& ev)
{
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
Graphics* g = ev.graphics();
gfx::Rect bounds = clientBounds();
gfx::Color bgcolor, fgcolor;
if (isSelected()) {
bgcolor = theme->colors.listitemSelectedFace();
fgcolor = theme->colors.listitemSelectedText();
}
else {
bgcolor = theme->colors.listitemNormalFace();
fgcolor = theme->colors.listitemNormalText();
}
Resource* resource() const {
return m_resource;
}
g->fillRect(bgcolor, bounds);
protected:
bool onProcessMessage(ui::Message* msg) override {
switch (msg->type()) {
case kMouseLeaveMessage:
case kMouseEnterMessage:
invalidate();
break;
}
return ListItem::onProcessMessage(msg);
}
static_cast<ResourcesListBox*>(parent())->
paintResource(g, bounds, m_resource);
void onPaint(PaintEvent& ev) override {
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
Graphics* g = ev.graphics();
gfx::Rect bounds = clientBounds();
gfx::Color bgcolor, fgcolor;
if (isSelected()) {
bgcolor = theme->colors.listitemSelectedFace();
fgcolor = theme->colors.listitemSelectedText();
}
else {
bgcolor = theme->colors.listitemNormalFace();
fgcolor = theme->colors.listitemNormalText();
}
g->fillRect(bgcolor, bounds);
g->drawString(text(), fgcolor, gfx::ColorNone,
gfx::Point(
bounds.x + guiscale()*2,
bounds.y + bounds.h/2 - g->measureUIString(text()).h/2));
}
void ResourceListItem::onSizeHint(SizeHintEvent& ev)
{
ev.setSizeHint(
static_cast<ResourcesListBox*>(parent())->
paintResource(g, bounds, m_resource);
resourceSizeHint(m_resource));
}
// for (int i=0; i<m_palette->size(); ++i) {
// doc::color_t c = m_resource->getEntry(i);
// g->fillRect(gfx::rgba(
// doc::rgba_getr(c),
// doc::rgba_getg(c),
// doc::rgba_getb(c)), box);
// box.x += box.w;
// }
g->drawString(text(), fgcolor, gfx::ColorNone,
gfx::Point(
bounds.x + guiscale()*2,
bounds.y + bounds.h/2 - g->measureUIString(text()).h/2));
}
void onSizeHint(SizeHintEvent& ev) override {
ev.setSizeHint(
static_cast<ResourcesListBox*>(parent())->
resourceSizeHint(m_resource));
}
private:
base::UniquePtr<Resource> m_resource;
};
//////////////////////////////////////////////////////////////////////
// ResourcesListBox::LoadingItem
class ResourcesListBox::LoadingItem : public ListItem {
public:
@ -118,6 +105,9 @@ private:
int m_state;
};
//////////////////////////////////////////////////////////////////////
// ResourcesListBox
ResourcesListBox::ResourcesListBox(ResourcesLoader* resourcesLoader)
: m_resourcesLoader(resourcesLoader)
, m_resourcesTimer(100)
@ -166,14 +156,9 @@ void ResourcesListBox::onChange()
onResourceChange(resource);
}
void ResourcesListBox::onResourceChange(Resource* resource)
ResourceListItem* ResourcesListBox::onCreateResourceItem(Resource* resource)
{
// Do nothing
}
void ResourcesListBox::onPaintResource(Graphics* g, const gfx::Rect& bounds, Resource* resource)
{
// Do nothing
return new ResourceListItem(resource);
}
void ResourcesListBox::onTick()
@ -201,7 +186,7 @@ void ResourcesListBox::onTick()
return;
}
base::UniquePtr<ResourceListItem> listItem(new ResourceListItem(resource));
base::UniquePtr<ResourceListItem> listItem(onCreateResourceItem(resource));
insertChild(getItemsCount()-1, listItem);
layout();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@ -11,29 +11,49 @@
#include "app/res/resources_loader.h"
#include "base/unique_ptr.h"
#include "ui/listbox.h"
#include "ui/listitem.h"
#include "ui/timer.h"
namespace app {
class ResourceListItem;
class ResourceListItem : public ui::ListItem {
public:
ResourceListItem(Resource* resource);
Resource* resource() const { return m_resource; }
protected:
bool onProcessMessage(ui::Message* msg) override;
void onPaint(ui::PaintEvent& ev) override;
void onSizeHint(ui::SizeHintEvent& ev) override;
private:
base::UniquePtr<Resource> m_resource;
};
class ResourcesListBox : public ui::ListBox {
public:
friend class ResourceListItem;
ResourcesListBox(ResourcesLoader* resourcesLoader);
Resource* selectedResource();
void paintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource);
gfx::Size resourceSizeHint(Resource* resource);
protected:
virtual bool onProcessMessage(ui::Message* msg) override;
virtual void onChange() override;
virtual void onResourceChange(Resource* resource) = 0;
virtual ResourceListItem* onCreateResourceItem(Resource* resource);
// abstract
virtual void onResourceChange(Resource* resource) = 0;
virtual void onPaintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource) = 0;
virtual void onResourceSizeHint(Resource* resource, gfx::Size& size) = 0;
private:
void paintResource(ui::Graphics* g, const gfx::Rect& bounds, Resource* resource);
gfx::Size resourceSizeHint(Resource* resource);
void onTick();
void stop();

View File

@ -1,5 +1,5 @@
// Aseprite Document Library
// Copyright (c) 2001-2015 David Capello
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -36,15 +36,25 @@ Palette* load_gpl_file(const char *filename)
if (line != "GIMP Palette") return NULL;
base::UniquePtr<Palette> pal(new Palette(frame_t(0), 0));
std::string comment;
while (std::getline(f, line)) {
// Trim line.
base::trim_string(line, line);
// Remove comments
if (line.empty() || line[0] == '#')
// Remove empty lines
if (line.empty())
continue;
// Concatenate comments
if (line[0] == '#') {
line = line.substr(1);
base::trim_string(line, line);
comment += line;
comment.push_back('\n');
continue;
}
// Remove properties (TODO add these properties in the palette)
if (!std::isdigit(line[0]))
continue;
@ -60,6 +70,12 @@ Palette* load_gpl_file(const char *filename)
pal->addEntry(rgba(r, g, b, 255));
}
base::trim_string(comment, comment);
if (!comment.empty()) {
LOG("%s comment: %s\n", filename, comment.c_str());
pal->setComment(comment);
}
return pal.release();
}

View File

@ -33,6 +33,7 @@ Palette::Palette(frame_t frame, int ncolors)
Palette::Palette(const Palette& palette)
: Object(palette)
, m_comment(palette.m_comment)
{
m_frame = palette.m_frame;
m_colors = palette.m_colors;
@ -41,6 +42,7 @@ Palette::Palette(const Palette& palette)
Palette::Palette(const Palette& palette, const Remap& remap)
: Object(palette)
, m_comment(palette.m_comment)
{
m_frame = palette.m_frame;

View File

@ -32,11 +32,17 @@ namespace doc {
int size() const { return (int)m_colors.size(); }
void resize(int ncolors);
std::string filename() const { return m_filename; }
const std::string& filename() const { return m_filename; }
const std::string& comment() const { return m_comment; }
void setFilename(const std::string& filename) {
m_filename = filename;
}
void setComment(const std::string& comment) {
m_comment = comment;
}
int getModifications() const { return m_modifications; }
// Return true if the palette has alpha != 255 in some entry
@ -91,6 +97,7 @@ namespace doc {
std::vector<color_t> m_colors;
int m_modifications;
std::string m_filename; // If the palette is associated with a file.
std::string m_comment; // Some extra comment from the .gpl file (author, website, etc.).
};
} // namespace doc