Skip to content

Commit fbeb7f6

Browse files
author
Gin
committed
Add file path option
1 parent bea59f8 commit fbeb7f6

File tree

6 files changed

+462
-1
lines changed

6 files changed

+462
-1
lines changed

Common/Cpp/Options/PathOption.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/* Path Option
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include "Common/Cpp/Containers/Pimpl.tpp"
8+
#include "Common/Cpp/Concurrency/SpinLock.h"
9+
#include "Common/Cpp/Json/JsonValue.h"
10+
#include "PathOption.h"
11+
12+
namespace PokemonAutomation{
13+
14+
15+
struct PathCell::Data{
16+
const std::string m_default;
17+
const std::string m_filter_string;
18+
const std::string m_placeholder_text;
19+
20+
std::atomic<bool> m_locked;
21+
22+
mutable SpinLock m_lock;
23+
std::string m_current;
24+
25+
Data(
26+
std::string default_value,
27+
std::string filter_string,
28+
std::string placeholder_text
29+
)
30+
: m_default(std::move(default_value))
31+
, m_filter_string(std::move(filter_string))
32+
, m_placeholder_text(std::move(placeholder_text))
33+
, m_current(m_default)
34+
{}
35+
};
36+
37+
38+
PathCell::~PathCell() = default;
39+
PathCell::PathCell(
40+
LockMode lock_while_program_is_running,
41+
std::string default_value,
42+
std::string filter_string,
43+
std::string placeholder_text
44+
)
45+
: ConfigOption(lock_while_program_is_running)
46+
, m_data(CONSTRUCT_TOKEN, std::move(default_value), std::move(filter_string), std::move(placeholder_text))
47+
{}
48+
49+
const std::string& PathCell::placeholder_text() const{
50+
return m_data->m_placeholder_text;
51+
}
52+
const std::string PathCell::default_value() const{
53+
return m_data->m_default;
54+
}
55+
const std::string& PathCell::filter_string() const{
56+
return m_data->m_filter_string;
57+
}
58+
59+
60+
bool PathCell::is_locked() const{
61+
return m_data->m_locked.load(std::memory_order_relaxed);
62+
}
63+
void PathCell::set_locked(bool locked){
64+
if (locked == is_locked()){
65+
return;
66+
}
67+
m_data->m_locked.store(locked, std::memory_order_relaxed);
68+
report_visibility_changed();
69+
}
70+
71+
72+
PathCell::operator std::string() const{
73+
ReadSpinLock lg(m_data->m_lock);
74+
return m_data->m_current;
75+
}
76+
void PathCell::set(std::string x){
77+
sanitize(x);
78+
{
79+
WriteSpinLock lg(m_data->m_lock);
80+
if (m_data->m_current == x){
81+
return;
82+
}
83+
m_data->m_current = std::move(x);
84+
}
85+
report_value_changed(this);
86+
}
87+
88+
void PathCell::load_json(const JsonValue& json){
89+
const std::string* str = json.to_string();
90+
if (str == nullptr){
91+
return;
92+
}
93+
set(*str);
94+
}
95+
JsonValue PathCell::to_json() const{
96+
ReadSpinLock lg(m_data->m_lock);
97+
return m_data->m_current;
98+
}
99+
100+
void PathCell::restore_defaults(){
101+
set(m_data->m_default);
102+
}
103+
104+
105+
106+
PathOption::PathOption(
107+
std::string label,
108+
LockMode lock_while_program_is_running,
109+
std::string default_value,
110+
std::string filter_string,
111+
std::string placeholder_text
112+
)
113+
: PathCell(lock_while_program_is_running, default_value, filter_string, placeholder_text)
114+
, m_label(std::move(label))
115+
{}
116+
117+
118+
119+
120+
121+
122+
123+
}

Common/Cpp/Options/PathOption.h

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/* Path Option
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#ifndef PokemonAutomation_Options_PathOption_H
8+
#define PokemonAutomation_Options_PathOption_H
9+
10+
#include "Common/Cpp/Containers/Pimpl.h"
11+
#include "Common/Cpp/Options/ConfigOption.h"
12+
13+
namespace PokemonAutomation{
14+
15+
16+
class PathCell : public ConfigOption{
17+
public:
18+
~PathCell();
19+
PathCell(
20+
LockMode lock_while_program_is_running,
21+
std::string default_value,
22+
std::string filter_string, // e.g. "*.json"
23+
std::string placeholder_text
24+
);
25+
26+
const std::string& placeholder_text() const;
27+
const std::string default_value() const;
28+
const std::string& filter_string() const;
29+
30+
31+
bool is_locked() const;
32+
void set_locked(bool locked);
33+
34+
operator std::string() const;
35+
void set(std::string x);
36+
37+
virtual void load_json(const JsonValue& json) override;
38+
virtual JsonValue to_json() const override;
39+
40+
virtual void restore_defaults() override;
41+
42+
virtual ConfigWidget* make_QtWidget(QWidget& parent) override;
43+
44+
protected:
45+
virtual void sanitize(std::string& str){}
46+
47+
private:
48+
struct Data;
49+
Pimpl<Data> m_data;
50+
};
51+
52+
53+
class PathOption : public PathCell{
54+
public:
55+
PathOption(
56+
std::string label,
57+
LockMode lock_while_program_is_running,
58+
std::string default_value,
59+
std::string filter_string,
60+
std::string placeholder_text
61+
);
62+
63+
const std::string& label() const{ return m_label; }
64+
65+
virtual ConfigWidget* make_QtWidget(QWidget& parent) override;
66+
67+
private:
68+
const std::string m_label;
69+
};
70+
71+
72+
73+
74+
}
75+
#endif
76+

Common/Qt/Options/PathWidget.cpp

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/* Path Option
2+
*
3+
* From: https://github.com/PokemonAutomation/
4+
*
5+
*/
6+
7+
#include <QHBoxLayout>
8+
#include <QLabel>
9+
#include <QLineEdit>
10+
#include <QPushButton>
11+
#include <QFileDialog>
12+
#include "PathWidget.h"
13+
14+
namespace PokemonAutomation{
15+
16+
17+
ConfigWidget* PathCell::make_QtWidget(QWidget& parent){
18+
return new PathCellWidget(parent, *this);
19+
}
20+
21+
ConfigWidget* PathOption::make_QtWidget(QWidget& parent){
22+
return new PathOptionWidget(parent, *this);
23+
}
24+
25+
26+
27+
PathCellWidget::~PathCellWidget(){
28+
m_value.remove_listener(*this);
29+
}
30+
PathCellWidget::PathCellWidget(QWidget& parent, PathCell& value)
31+
: QWidget(&parent)
32+
, ConfigWidget(value, *this)
33+
, m_value(value)
34+
{
35+
QHBoxLayout* layout = new QHBoxLayout(this);
36+
layout->setContentsMargins(0, 0, 0, 0);
37+
38+
m_line_edit = new QLineEdit(QString::fromStdString(value), this);
39+
m_line_edit->setPlaceholderText(QString::fromStdString(value.placeholder_text()));
40+
m_line_edit->setReadOnly(value.lock_mode() == LockMode::READ_ONLY || m_value.is_locked());
41+
layout->addWidget(m_line_edit, 1);
42+
43+
m_browse_button = new QPushButton("Browse...", this);
44+
m_browse_button->setEnabled(value.lock_mode() != LockMode::READ_ONLY && !m_value.is_locked());
45+
layout->addWidget(m_browse_button);
46+
47+
connect(
48+
m_line_edit, &QLineEdit::editingFinished,
49+
this, [this](){
50+
m_value.set(m_line_edit->text().toStdString());
51+
}
52+
);
53+
54+
connect(
55+
m_browse_button, &QPushButton::clicked,
56+
this, [this](){
57+
browse_file();
58+
}
59+
);
60+
61+
m_value.add_listener(*this);
62+
}
63+
64+
void PathCellWidget::browse_file(){
65+
QString current_path = m_line_edit->text();
66+
QString file_path = QFileDialog::getOpenFileName(
67+
this,
68+
"Select File",
69+
current_path,
70+
QString::fromStdString(m_value.filter_string())
71+
);
72+
73+
if (!file_path.isEmpty()){
74+
m_line_edit->setText(file_path);
75+
m_value.set(file_path.toStdString());
76+
}
77+
}
78+
79+
void PathCellWidget::update_value(){
80+
m_line_edit->setText(QString::fromStdString(m_value));
81+
}
82+
void PathCellWidget::on_config_value_changed(void* object){
83+
QMetaObject::invokeMethod(this, [this]{
84+
update_value();
85+
}, Qt::QueuedConnection);
86+
}
87+
void PathCellWidget::on_config_visibility_changed(){
88+
this->setEnabled(true);
89+
QMetaObject::invokeMethod(this, [this]{
90+
const ConfigOptionState visibility = m_value.visibility();
91+
m_line_edit->setReadOnly(visibility != ConfigOptionState::ENABLED ||
92+
m_value.lock_mode() == LockMode::READ_ONLY || m_value.is_locked());
93+
m_browse_button->setEnabled(visibility == ConfigOptionState::ENABLED &&
94+
m_value.lock_mode() != LockMode::READ_ONLY && !m_value.is_locked());
95+
switch (visibility){
96+
case ConfigOptionState::ENABLED:
97+
case ConfigOptionState::DISABLED:
98+
this->setVisible(true);
99+
break;
100+
case ConfigOptionState::HIDDEN:
101+
this->setVisible(false);
102+
break;
103+
}
104+
}, Qt::QueuedConnection);
105+
}
106+
107+
108+
109+
110+
PathOptionWidget::~PathOptionWidget(){
111+
m_value.remove_listener(*this);
112+
}
113+
PathOptionWidget::PathOptionWidget(QWidget& parent, PathOption& value)
114+
: QWidget(&parent)
115+
, ConfigWidget(value, *this)
116+
, m_value(value)
117+
{
118+
QHBoxLayout* layout = new QHBoxLayout(this);
119+
layout->setContentsMargins(0, 0, 0, 0);
120+
QLabel* text = new QLabel(QString::fromStdString(value.label()), this);
121+
text->setWordWrap(true);
122+
layout->addWidget(text, 1);
123+
124+
m_line_edit = new QLineEdit(QString::fromStdString(m_value), this);
125+
m_line_edit->setPlaceholderText(QString::fromStdString(value.placeholder_text()));
126+
m_line_edit->setReadOnly(value.lock_mode() == LockMode::READ_ONLY);
127+
layout->addWidget(m_line_edit, 1);
128+
129+
m_browse_button = new QPushButton("Browse...", this);
130+
m_browse_button->setEnabled(value.lock_mode() != LockMode::READ_ONLY);
131+
layout->addWidget(m_browse_button);
132+
133+
connect(
134+
m_line_edit, &QLineEdit::editingFinished,
135+
this, [this](){
136+
m_value.set(m_line_edit->text().toStdString());
137+
}
138+
);
139+
140+
connect(
141+
m_browse_button, &QPushButton::clicked,
142+
this, [this](){
143+
browse_file();
144+
}
145+
);
146+
147+
m_value.add_listener(*this);
148+
}
149+
150+
void PathOptionWidget::browse_file(){
151+
QString current_path = m_line_edit->text();
152+
QString file_path = QFileDialog::getOpenFileName(
153+
this,
154+
"Select File",
155+
current_path,
156+
QString::fromStdString(m_value.filter_string())
157+
);
158+
159+
if (!file_path.isEmpty()){
160+
m_line_edit->setText(file_path);
161+
m_value.set(file_path.toStdString());
162+
}
163+
}
164+
165+
void PathOptionWidget::update_value(){
166+
m_line_edit->setText(QString::fromStdString(m_value));
167+
}
168+
void PathOptionWidget::on_config_value_changed(void* object){
169+
QMetaObject::invokeMethod(m_line_edit, [this]{
170+
update_value();
171+
}, Qt::QueuedConnection);
172+
}
173+
void PathOptionWidget::on_config_visibility_changed(){
174+
this->setEnabled(true);
175+
QMetaObject::invokeMethod(this, [this]{
176+
const ConfigOptionState visibility = m_value.visibility();
177+
m_line_edit->setReadOnly(visibility != ConfigOptionState::ENABLED ||
178+
m_value.lock_mode() == LockMode::READ_ONLY || m_value.is_locked());
179+
m_browse_button->setEnabled(visibility == ConfigOptionState::ENABLED &&
180+
m_value.lock_mode() != LockMode::READ_ONLY && !m_value.is_locked());
181+
switch (visibility){
182+
case ConfigOptionState::ENABLED:
183+
case ConfigOptionState::DISABLED:
184+
this->setVisible(true);
185+
break;
186+
case ConfigOptionState::HIDDEN:
187+
this->setVisible(false);
188+
break;
189+
}
190+
}, Qt::QueuedConnection);
191+
}
192+
193+
194+
195+
196+
197+
}

0 commit comments

Comments
 (0)