mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-16 05:42:32 +00:00
Add Dialog:file() (#1997, fix aseprite/api#7)
This commit is contained in:
parent
b3eba1c952
commit
e0e83f0d40
@ -619,7 +619,6 @@ new_version_available = New {0} v{1} available!
|
|||||||
|
|
||||||
[import_sprite_sheet]
|
[import_sprite_sheet]
|
||||||
title = Import Sprite Sheet
|
title = Import Sprite Sheet
|
||||||
select_file = Select File
|
|
||||||
type = Type:
|
type = Type:
|
||||||
tiles = Tiles:
|
tiles = Tiles:
|
||||||
x = X:
|
x = X:
|
||||||
@ -1182,6 +1181,10 @@ assigned_to = Assigned to:
|
|||||||
ok = OK
|
ok = OK
|
||||||
cancel = Cancel
|
cancel = Cancel
|
||||||
|
|
||||||
|
[select_file]
|
||||||
|
text = Select File
|
||||||
|
browse = ...
|
||||||
|
|
||||||
[send_crash]
|
[send_crash]
|
||||||
title = Crash Report
|
title = Crash Report
|
||||||
send_file = Please send the following file:
|
send_file = Please send the following file:
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<window id="import_sprite_sheet" text="@.title">
|
<window id="import_sprite_sheet" text="@.title">
|
||||||
<vbox>
|
<vbox>
|
||||||
<grid columns="4">
|
<grid columns="4">
|
||||||
<button id="select_file" text="@.select_file" cell_hspan="4" />
|
<button id="select_file" text="@select_file.text" cell_hspan="4" />
|
||||||
|
|
||||||
<label text="@.type" />
|
<label text="@.type" />
|
||||||
<combobox id="sheet_type" cell_hspan="3" />
|
<combobox id="sheet_type" cell_hspan="3" />
|
||||||
|
@ -363,6 +363,7 @@ if(ENABLE_UI)
|
|||||||
ui/file_list.cpp
|
ui/file_list.cpp
|
||||||
ui/file_list_view.cpp
|
ui/file_list_view.cpp
|
||||||
ui/file_selector.cpp
|
ui/file_selector.cpp
|
||||||
|
ui/filename_field.cpp
|
||||||
ui/font_popup.cpp
|
ui/font_popup.cpp
|
||||||
ui/frame_tag_window.cpp
|
ui/frame_tag_window.cpp
|
||||||
ui/hex_color_entry.cpp
|
ui/hex_color_entry.cpp
|
||||||
|
@ -485,8 +485,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onFileNamesChange() {
|
void onFileNamesChange() {
|
||||||
imageFilename()->setText("Select File: " + base::get_file_name(m_filename));
|
imageFilename()->setText(base::get_file_name(m_filename));
|
||||||
dataFilename()->setText("Select File: " + base::get_file_name(m_dataFilename));
|
dataFilename()->setText(base::get_file_name(m_dataFilename));
|
||||||
resize();
|
resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,10 +12,14 @@
|
|||||||
#include "app/app.h"
|
#include "app/app.h"
|
||||||
#include "app/color.h"
|
#include "app/color.h"
|
||||||
#include "app/color_utils.h"
|
#include "app/color_utils.h"
|
||||||
|
#include "app/file_selector.h"
|
||||||
#include "app/script/engine.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/script/luacpp.h"
|
#include "app/script/luacpp.h"
|
||||||
#include "app/ui/color_button.h"
|
#include "app/ui/color_button.h"
|
||||||
#include "app/ui/expr_entry.h"
|
#include "app/ui/expr_entry.h"
|
||||||
|
#include "app/ui/filename_field.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "base/paths.h"
|
||||||
#include "ui/box.h"
|
#include "ui/box.h"
|
||||||
#include "ui/button.h"
|
#include "ui/button.h"
|
||||||
#include "ui/combobox.h"
|
#include "ui/combobox.h"
|
||||||
@ -27,6 +31,7 @@
|
|||||||
#include "ui/window.h"
|
#include "ui/window.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
namespace script {
|
namespace script {
|
||||||
@ -87,6 +92,53 @@ struct Dialog {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename Signal,
|
||||||
|
typename Callback>
|
||||||
|
void Dialog_connect_signal(lua_State* L,
|
||||||
|
Signal& signal,
|
||||||
|
Callback callback)
|
||||||
|
{
|
||||||
|
auto dlg = get_obj<Dialog>(L, 1);
|
||||||
|
|
||||||
|
// Add a reference to the onclick function
|
||||||
|
const int ref = dlg->callbacksTableRef;
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||||
|
lua_len(L, -1);
|
||||||
|
const int n = 1+lua_tointegerx(L, -1, nullptr);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pushvalue(L, -2); // Copy the function in onclick
|
||||||
|
lua_seti(L, -2, n); // Put the copy of the function in the callbacksTableRef
|
||||||
|
|
||||||
|
signal.connect(
|
||||||
|
base::Bind<void>([=]() {
|
||||||
|
callback();
|
||||||
|
try {
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
||||||
|
lua_geti(L, -1, n);
|
||||||
|
|
||||||
|
if (lua_isfunction(L, -1)) {
|
||||||
|
if (lua_pcall(L, 0, 0, 0)) {
|
||||||
|
if (const char* s = lua_tostring(L, -1))
|
||||||
|
App::instance()
|
||||||
|
->scriptEngine()
|
||||||
|
->consolePrint(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lua_pop(L, 1);
|
||||||
|
lua_pop(L, 1); // Pop table from the registry
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex) {
|
||||||
|
// This is used to catch unhandled exception or for
|
||||||
|
// example, std::runtime_error exceptions when a Tx() is
|
||||||
|
// created without an active sprite.
|
||||||
|
App::instance()
|
||||||
|
->scriptEngine()
|
||||||
|
->consolePrint(ex.what());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
int Dialog_new(lua_State* L)
|
int Dialog_new(lua_State* L)
|
||||||
{
|
{
|
||||||
auto dlg = push_new<Dialog>(L);
|
auto dlg = push_new<Dialog>(L);
|
||||||
@ -255,8 +307,6 @@ int Dialog_label(lua_State* L)
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
int Dialog_button_base(lua_State* L, T** outputWidget = nullptr)
|
int Dialog_button_base(lua_State* L, T** outputWidget = nullptr)
|
||||||
{
|
{
|
||||||
auto dlg = get_obj<Dialog>(L, 1);
|
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
if (lua_istable(L, 2)) {
|
if (lua_istable(L, 2)) {
|
||||||
int type = lua_getfield(L, 2, "text");
|
int type = lua_getfield(L, 2, "text");
|
||||||
@ -283,43 +333,11 @@ int Dialog_button_base(lua_State* L, T** outputWidget = nullptr)
|
|||||||
|
|
||||||
type = lua_getfield(L, 2, "onclick");
|
type = lua_getfield(L, 2, "onclick");
|
||||||
if (type == LUA_TFUNCTION) {
|
if (type == LUA_TFUNCTION) {
|
||||||
// Add a reference to the onclick function
|
auto dlg = get_obj<Dialog>(L, 1);
|
||||||
const int ref = dlg->callbacksTableRef;
|
Dialog_connect_signal(L, widget->Click,
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
[dlg, widget]{
|
||||||
lua_len(L, -1);
|
dlg->lastButton = widget;
|
||||||
const int n = 1+lua_tointegerx(L, -1, nullptr);
|
});
|
||||||
lua_pop(L, 1);
|
|
||||||
lua_pushvalue(L, -2); // Copy the function in onclick
|
|
||||||
lua_seti(L, -2, n); // Put the copy of the function in the callbacksTableRef
|
|
||||||
widget->Click.connect(
|
|
||||||
[dlg, widget, L, ref, n](ui::Event& ev) {
|
|
||||||
dlg->lastButton = widget;
|
|
||||||
|
|
||||||
try {
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
|
||||||
lua_geti(L, -1, n);
|
|
||||||
|
|
||||||
if (lua_isfunction(L, -1)) {
|
|
||||||
if (lua_pcall(L, 0, 0, 0)) {
|
|
||||||
if (const char* s = lua_tostring(L, -1))
|
|
||||||
App::instance()
|
|
||||||
->scriptEngine()
|
|
||||||
->consolePrint(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
lua_pop(L, 1);
|
|
||||||
lua_pop(L, 1); // Pop table from the registry
|
|
||||||
}
|
|
||||||
catch (const std::exception& ex) {
|
|
||||||
// This is used to catch unhandled exception or for
|
|
||||||
// example, std::runtime_error exceptions when a Tx() is
|
|
||||||
// created without an active sprite.
|
|
||||||
App::instance()
|
|
||||||
->scriptEngine()
|
|
||||||
->consolePrint(ex.what());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
closeWindowByDefault = false;
|
closeWindowByDefault = false;
|
||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
@ -480,6 +498,74 @@ int Dialog_color(lua_State* L)
|
|||||||
return Dialog_add_widget(L, widget);
|
return Dialog_add_widget(L, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Dialog_file(lua_State* L)
|
||||||
|
{
|
||||||
|
std::string title = "Open File";
|
||||||
|
std::string fn;
|
||||||
|
base::paths exts;
|
||||||
|
auto dlgType = FileSelectorType::Open;
|
||||||
|
auto fnFieldType = FilenameField::ButtonOnly;
|
||||||
|
|
||||||
|
if (lua_istable(L, 2)) {
|
||||||
|
lua_getfield(L, 2, "filename");
|
||||||
|
if (auto p = lua_tostring(L, -1))
|
||||||
|
fn = p;
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
int type = lua_getfield(L, 2, "save");
|
||||||
|
if (type == LUA_TBOOLEAN) {
|
||||||
|
dlgType = FileSelectorType::Save;
|
||||||
|
title = "Save File";
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
type = lua_getfield(L, 2, "title");
|
||||||
|
if (type == LUA_TSTRING)
|
||||||
|
title = lua_tostring(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
type = lua_getfield(L, 2, "entry");
|
||||||
|
if (type == LUA_TBOOLEAN) {
|
||||||
|
fnFieldType = FilenameField::EntryAndButton;
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
type = lua_getfield(L, 2, "filetypes");
|
||||||
|
if (type == LUA_TTABLE) {
|
||||||
|
lua_pushnil(L);
|
||||||
|
while (lua_next(L, -2) != 0) {
|
||||||
|
if (auto p = lua_tostring(L, -1))
|
||||||
|
exts.push_back(p);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto widget = new FilenameField(fnFieldType, fn);
|
||||||
|
|
||||||
|
if (lua_istable(L, 2)) {
|
||||||
|
int type = lua_getfield(L, 2, "onchange");
|
||||||
|
if (type == LUA_TFUNCTION) {
|
||||||
|
Dialog_connect_signal(L, widget->Change, []{ });
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
widget->SelectFile.connect(
|
||||||
|
[=]() -> std::string {
|
||||||
|
base::paths newfilename;
|
||||||
|
if (app::show_file_selector(
|
||||||
|
title, widget->filename(), exts,
|
||||||
|
dlgType,
|
||||||
|
newfilename))
|
||||||
|
return newfilename.front();
|
||||||
|
else
|
||||||
|
return widget->filename();
|
||||||
|
});
|
||||||
|
return Dialog_add_widget(L, widget);
|
||||||
|
}
|
||||||
|
|
||||||
int Dialog_get_data(lua_State* L)
|
int Dialog_get_data(lua_State* L)
|
||||||
{
|
{
|
||||||
auto dlg = get_obj<Dialog>(L, 1);
|
auto dlg = get_obj<Dialog>(L, 1);
|
||||||
@ -524,6 +610,8 @@ int Dialog_get_data(lua_State* L)
|
|||||||
default:
|
default:
|
||||||
if (auto colorButton = dynamic_cast<const ColorButton*>(widget))
|
if (auto colorButton = dynamic_cast<const ColorButton*>(widget))
|
||||||
push_obj<app::Color>(L, colorButton->getColor());
|
push_obj<app::Color>(L, colorButton->getColor());
|
||||||
|
else if (auto filenameField = dynamic_cast<const FilenameField*>(widget))
|
||||||
|
lua_pushstring(L, filenameField->filename().c_str());
|
||||||
else
|
else
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
break;
|
break;
|
||||||
@ -581,6 +669,10 @@ int Dialog_set_data(lua_State* L)
|
|||||||
default:
|
default:
|
||||||
if (auto colorButton = dynamic_cast<ColorButton*>(widget))
|
if (auto colorButton = dynamic_cast<ColorButton*>(widget))
|
||||||
colorButton->setColor(convert_args_into_color(L, -1));
|
colorButton->setColor(convert_args_into_color(L, -1));
|
||||||
|
else if (auto filenameField = dynamic_cast<FilenameField*>(widget)) {
|
||||||
|
if (auto p = lua_tostring(L, -1))
|
||||||
|
filenameField->setFilename(p);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,6 +713,7 @@ const luaL_Reg Dialog_methods[] = {
|
|||||||
{ "slider", Dialog_slider },
|
{ "slider", Dialog_slider },
|
||||||
{ "combobox", Dialog_combobox },
|
{ "combobox", Dialog_combobox },
|
||||||
{ "color", Dialog_color },
|
{ "color", Dialog_color },
|
||||||
|
{ "file", Dialog_file },
|
||||||
{ nullptr, nullptr }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
118
src/app/ui/filename_field.cpp
Normal file
118
src/app/ui/filename_field.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "app/ui/filename_field.h"
|
||||||
|
|
||||||
|
#include "app/i18n/strings.h"
|
||||||
|
#include "app/ui/skin/skin_theme.h"
|
||||||
|
#include "base/bind.h"
|
||||||
|
#include "base/fs.h"
|
||||||
|
#include "ui/box.h"
|
||||||
|
#include "ui/button.h"
|
||||||
|
#include "ui/entry.h"
|
||||||
|
#include "ui/message.h"
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
using namespace ui;
|
||||||
|
|
||||||
|
FilenameField::FilenameField(const Type type,
|
||||||
|
const std::string& pathAndFilename)
|
||||||
|
: m_entry(type == EntryAndButton ? new ui::Entry(1024, ""): nullptr)
|
||||||
|
, m_button(type == EntryAndButton ? Strings::select_file_browse():
|
||||||
|
Strings::select_file_text())
|
||||||
|
{
|
||||||
|
setFocusStop(true);
|
||||||
|
if (m_entry) {
|
||||||
|
m_entry->setExpansive(true);
|
||||||
|
addChild(m_entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_button.setExpansive(true);
|
||||||
|
}
|
||||||
|
addChild(&m_button);
|
||||||
|
|
||||||
|
setFilename(pathAndFilename);
|
||||||
|
|
||||||
|
if (m_entry) {
|
||||||
|
m_entry->Change.connect(
|
||||||
|
base::Bind<void>(
|
||||||
|
[this]{
|
||||||
|
m_file = m_entry->text();
|
||||||
|
Change();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_button.Click.connect(
|
||||||
|
base::Bind<void>(
|
||||||
|
[this]{
|
||||||
|
std::string fn = SelectFile();
|
||||||
|
if (!fn.empty()) {
|
||||||
|
setFilename(fn);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
initTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FilenameField::filename() const
|
||||||
|
{
|
||||||
|
return base::join_path(m_path, m_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilenameField::setFilename(const std::string& fn)
|
||||||
|
{
|
||||||
|
if (filename() == fn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_path = base::get_file_path(fn);
|
||||||
|
m_file = base::get_file_name(fn);
|
||||||
|
updateWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FilenameField::onProcessMessage(ui::Message* msg)
|
||||||
|
{
|
||||||
|
switch (msg->type()) {
|
||||||
|
case ui::kFocusEnterMessage:
|
||||||
|
if (manager()->getFocus() == this) {
|
||||||
|
if (m_entry)
|
||||||
|
m_entry->requestFocus();
|
||||||
|
else
|
||||||
|
m_button.requestFocus();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return HBox::onProcessMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilenameField::onInitTheme(ui::InitThemeEvent& ev)
|
||||||
|
{
|
||||||
|
HBox::onInitTheme(ev);
|
||||||
|
setChildSpacing(0);
|
||||||
|
|
||||||
|
auto theme = skin::SkinTheme::instance();
|
||||||
|
ui::Style* style = theme->styles.miniButton();
|
||||||
|
if (style)
|
||||||
|
m_button.setStyle(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilenameField::updateWidgets()
|
||||||
|
{
|
||||||
|
if (m_entry)
|
||||||
|
m_entry->setText(m_file);
|
||||||
|
else if (m_file.empty())
|
||||||
|
m_button.setText(Strings::select_file_text());
|
||||||
|
else
|
||||||
|
m_button.setText(m_file);
|
||||||
|
|
||||||
|
Change();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace app
|
48
src/app/ui/filename_field.h
Normal file
48
src/app/ui/filename_field.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Aseprite
|
||||||
|
// Copyright (C) 2019 Igara Studio S.A.
|
||||||
|
//
|
||||||
|
// This program is distributed under the terms of
|
||||||
|
// the End-User License Agreement for Aseprite.
|
||||||
|
|
||||||
|
#ifndef APP_UI_FILENAME_FIELD_H_INCLUDED
|
||||||
|
#define APP_UI_FILENAME_FIELD_H_INCLUDED
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "obs/signal.h"
|
||||||
|
#include "ui/box.h"
|
||||||
|
#include "ui/button.h"
|
||||||
|
#include "ui/entry.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
class FilenameField : public ui::HBox {
|
||||||
|
public:
|
||||||
|
enum Type { EntryAndButton, ButtonOnly };
|
||||||
|
|
||||||
|
FilenameField(const Type type,
|
||||||
|
const std::string& pathAndFilename);
|
||||||
|
|
||||||
|
std::string filename() const;
|
||||||
|
void setFilename(const std::string& fn);
|
||||||
|
|
||||||
|
obs::signal<std::string()> SelectFile;
|
||||||
|
obs::signal<void()> Change;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool onProcessMessage(ui::Message* msg) override;
|
||||||
|
void onInitTheme(ui::InitThemeEvent& ev) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateWidgets();
|
||||||
|
|
||||||
|
std::string m_path;
|
||||||
|
std::string m_file;
|
||||||
|
ui::Entry* m_entry;
|
||||||
|
ui::Button m_button;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user