1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#include "bspf.hxx"
19#include "Dialog.hxx"
20#include "FSNode.hxx"
21#include "GuiObject.hxx"
22#include "OSystem.hxx"
23#include "EditTextWidget.hxx"
24#include "FileListWidget.hxx"
25#include "Widget.hxx"
26#include "Font.hxx"
27#include "BrowserDialog.hxx"
28
29/* We want to use this as a general directory selector at some point... possible uses
30 * - to select the data dir for a game
31 * - to select the place where save games are stored
32 * - others???
33 */
34// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font,
36 int max_w, int max_h, const string& title)
37 : Dialog(boss->instance(), boss->parent(), font, title),
38 CommandSender(boss),
39 _cmd(0),
40 _mode(FileSave)
41{
42 // Set real dimensions
43 _w = max_w;
44 _h = max_h;
45
46 const int lineHeight = font.getLineHeight(),
47 buttonWidth = font.getStringWidth("Defaults") + 20,
48 buttonHeight = font.getLineHeight() + 4,
49 selectHeight = lineHeight + 12;
50 int xpos, ypos;
51 ButtonWidget* b;
52
53 xpos = 10; ypos = 4 + _th;
54
55 // Current path - TODO: handle long paths ?
56 StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos + 2, "Path ");
57 _currentPath = new EditTextWidget(this, font, xpos + t->getWidth(), ypos,
58 _w - t->getWidth() - 2 * xpos, lineHeight);
59 _currentPath->setEditable(false);
60 // Add file list
61 ypos += lineHeight + 8;
62 _fileList = new FileListWidget(this, font, xpos, ypos, _w - 2 * xpos,
63 _h - selectHeight - buttonHeight - ypos - 20);
64 _fileList->setEditable(false);
65 addFocusWidget(_fileList);
66
67 // Add currently selected item
68 ypos += _fileList->getHeight() + 8;
69
70 _type = new StaticTextWidget(this, font, xpos, ypos + 2, "Name ");
71 _selected = new EditTextWidget(this, font, xpos + _type->getWidth(), ypos,
72 _w - _type->getWidth() - 2 * xpos, lineHeight, "");
73 _selected->setEditable(false);
74
75 // Buttons
76 _goUpButton = new ButtonWidget(this, font, 10, _h - buttonHeight - 10,
77 buttonWidth, buttonHeight, "Go up", kGoUpCmd);
78 addFocusWidget(_goUpButton);
79
80 _basedirButton =
81 new ButtonWidget(this, font, 15 + buttonWidth, _h - buttonHeight - 10,
82 buttonWidth, buttonHeight, "Base Dir", kBaseDirCmd);
83 addFocusWidget(_basedirButton);
84
85#ifndef BSPF_MACOS
86 b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10,
87 buttonWidth, buttonHeight, "Choose", kChooseCmd);
88 addFocusWidget(b);
89 addOKWidget(b);
90 b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10,
91 buttonWidth, buttonHeight, "Cancel", GuiObject::kCloseCmd);
92 addFocusWidget(b);
93 addCancelWidget(b);
94#else
95 b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10,
96 buttonWidth, buttonHeight, "Cancel", GuiObject::kCloseCmd);
97 addFocusWidget(b);
98 addCancelWidget(b);
99 b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10,
100 buttonWidth, buttonHeight, "Choose", kChooseCmd);
101 addFocusWidget(b);
102 addOKWidget(b);
103#endif
104}
105
106// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
107void BrowserDialog::show(const string& startpath,
108 BrowserDialog::ListMode mode, int cmd,
109 const string& ext)
110{
111 _cmd = cmd;
112 _mode = mode;
113
114 switch(_mode)
115 {
116 case FileLoad:
117 _fileList->setListMode(FilesystemNode::ListMode::All);
118 _fileList->setNameFilter([&ext](const FilesystemNode& node) {
119 return BSPF::endsWithIgnoreCase(node.getName(), ext);
120 });
121 _selected->setEditable(false);
122 _selected->clearFlags(Widget::FLAG_INVISIBLE);
123 _type->clearFlags(Widget::FLAG_INVISIBLE);
124 break;
125
126 case FileSave:
127 _fileList->setListMode(FilesystemNode::ListMode::All);
128 _fileList->setNameFilter([&ext](const FilesystemNode& node) {
129 return BSPF::endsWithIgnoreCase(node.getName(), ext);
130 });
131 _selected->setEditable(false); // FIXME - disable user input for now
132 _selected->clearFlags(Widget::FLAG_INVISIBLE);
133 _type->clearFlags(Widget::FLAG_INVISIBLE);
134 break;
135
136 case Directories:
137 _fileList->setListMode(FilesystemNode::ListMode::DirectoriesOnly);
138 _fileList->setNameFilter([](const FilesystemNode&) { return true; });
139 _selected->setEditable(false);
140 _selected->setFlags(Widget::FLAG_INVISIBLE);
141 _type->setFlags(Widget::FLAG_INVISIBLE);
142 break;
143 }
144
145 // Set start path
146 _fileList->setDirectory(FilesystemNode(startpath));
147
148 updateUI();
149
150 // Finally, open the dialog after it has been fully updated
151 open();
152}
153
154// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155const FilesystemNode& BrowserDialog::getResult() const
156{
157 if(_mode == FileLoad || _mode == FileSave)
158 return _fileList->selected();
159 else
160 return _fileList->currentDir();
161}
162
163// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
164void BrowserDialog::updateUI()
165{
166 // Only hilite the 'up' button if there's a parent directory
167 _goUpButton->setEnabled(_fileList->currentDir().hasParent());
168
169 // Update the path display
170 _currentPath->setText(_fileList->currentDir().getShortPath());
171
172 // Enable/disable OK button based on current mode
173 bool enable = _mode == Directories || !_fileList->selected().isDirectory();
174 _okWidget->setEnabled(enable);
175
176 if(!_fileList->selected().isDirectory())
177 _selected->setText(_fileList->getSelectedString());
178 else
179 _selected->setText("");
180}
181
182// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183void BrowserDialog::handleCommand(CommandSender* sender, int cmd,
184 int data, int id)
185{
186 switch (cmd)
187 {
188 case kChooseCmd:
189 case FileListWidget::ItemActivated:
190 // Send a signal to the calling class that a selection has been made
191 // Since we aren't derived from a widget, we don't have a 'data' or 'id'
192 if(_cmd) sendCommand(_cmd, -1, -1);
193 close();
194 break;
195
196 case kGoUpCmd:
197 _fileList->selectParent();
198 break;
199
200 case kBaseDirCmd:
201 _fileList->setDirectory(FilesystemNode(instance().baseDir()));
202 break;
203
204 case FileListWidget::ItemChanged:
205 updateUI();
206 break;
207
208 default:
209 Dialog::handleCommand(sender, cmd, data, 0);
210 break;
211 }
212}
213