File chooser widget added. Now used in the editor for save as and load.
This commit is contained in:
parent
0bdf49c8df
commit
6fab335aa4
11 changed files with 645 additions and 16 deletions
|
@ -79,6 +79,7 @@ wesnoth_SOURCES = about.cpp \
|
|||
unit_types.cpp \
|
||||
video.cpp \
|
||||
widgets/button.cpp \
|
||||
widgets/file_chooser.cpp \
|
||||
widgets/combo.cpp \
|
||||
widgets/menu.cpp \
|
||||
widgets/scrollbar.cpp \
|
||||
|
@ -142,6 +143,7 @@ wesnoth_SOURCES = about.cpp \
|
|||
util.hpp \
|
||||
video.hpp \
|
||||
widgets/button.hpp \
|
||||
widgets/file_chooser.hpp \
|
||||
widgets/combo.hpp \
|
||||
widgets/menu.hpp \
|
||||
widgets/scrollbar.hpp \
|
||||
|
@ -208,6 +210,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
|
|||
unit_types.cpp \
|
||||
video.cpp \
|
||||
widgets/button.cpp \
|
||||
widgets/file_chooser.cpp \
|
||||
widgets/menu.cpp \
|
||||
widgets/textbox.cpp \
|
||||
widgets/scrollbar.cpp \
|
||||
|
@ -267,6 +270,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
|
|||
unit_types.hpp \
|
||||
video.hpp \
|
||||
widgets/button.hpp \
|
||||
widgets/file_chooser.hpp \
|
||||
widgets/menu.hpp \
|
||||
widgets/textbox.hpp \
|
||||
widgets/scrollbar.hpp \
|
||||
|
|
|
@ -221,6 +221,7 @@ wesnoth_SOURCES = about.cpp \
|
|||
unit_types.cpp \
|
||||
video.cpp \
|
||||
widgets/button.cpp \
|
||||
widgets/file_chooser.cpp \
|
||||
widgets/combo.cpp \
|
||||
widgets/menu.cpp \
|
||||
widgets/scrollbar.cpp \
|
||||
|
@ -284,6 +285,7 @@ wesnoth_SOURCES = about.cpp \
|
|||
util.hpp \
|
||||
video.hpp \
|
||||
widgets/button.hpp \
|
||||
widgets/file_chooser.hpp \
|
||||
widgets/combo.hpp \
|
||||
widgets/menu.hpp \
|
||||
widgets/scrollbar.hpp \
|
||||
|
@ -351,6 +353,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
|
|||
unit_types.cpp \
|
||||
video.cpp \
|
||||
widgets/button.cpp \
|
||||
widgets/file_chooser.cpp \
|
||||
widgets/menu.cpp \
|
||||
widgets/textbox.cpp \
|
||||
widgets/scrollbar.cpp \
|
||||
|
@ -410,6 +413,7 @@ wesnoth_editor_SOURCES = editor/editor.cpp \
|
|||
unit_types.hpp \
|
||||
video.hpp \
|
||||
widgets/button.hpp \
|
||||
widgets/file_chooser.hpp \
|
||||
widgets/menu.hpp \
|
||||
widgets/textbox.hpp \
|
||||
widgets/scrollbar.hpp \
|
||||
|
@ -450,8 +454,9 @@ am_wesnoth_OBJECTS = about.$(OBJEXT) actions.$(OBJEXT) ai.$(OBJEXT) \
|
|||
terrain.$(OBJEXT) theme.$(OBJEXT) titlescreen.$(OBJEXT) \
|
||||
tooltips.$(OBJEXT) unit.$(OBJEXT) unit_display.$(OBJEXT) \
|
||||
unit_types.$(OBJEXT) video.$(OBJEXT) button.$(OBJEXT) \
|
||||
combo.$(OBJEXT) menu.$(OBJEXT) scrollbar.$(OBJEXT) \
|
||||
slider.$(OBJEXT) textbox.$(OBJEXT) widget.$(OBJEXT)
|
||||
file_chooser.$(OBJEXT) combo.$(OBJEXT) menu.$(OBJEXT) \
|
||||
scrollbar.$(OBJEXT) slider.$(OBJEXT) textbox.$(OBJEXT) \
|
||||
widget.$(OBJEXT)
|
||||
wesnoth_OBJECTS = $(am_wesnoth_OBJECTS)
|
||||
wesnoth_LDADD = $(LDADD)
|
||||
wesnoth_DEPENDENCIES =
|
||||
|
@ -475,8 +480,9 @@ am_wesnoth_editor_OBJECTS = editor.$(OBJEXT) editor_layout.$(OBJEXT) \
|
|||
statistics.$(OBJEXT) team.$(OBJEXT) terrain.$(OBJEXT) \
|
||||
theme.$(OBJEXT) tooltips.$(OBJEXT) unit.$(OBJEXT) \
|
||||
unit_display.$(OBJEXT) unit_types.$(OBJEXT) video.$(OBJEXT) \
|
||||
button.$(OBJEXT) menu.$(OBJEXT) textbox.$(OBJEXT) \
|
||||
scrollbar.$(OBJEXT) slider.$(OBJEXT) widget.$(OBJEXT)
|
||||
button.$(OBJEXT) file_chooser.$(OBJEXT) menu.$(OBJEXT) \
|
||||
textbox.$(OBJEXT) scrollbar.$(OBJEXT) slider.$(OBJEXT) \
|
||||
widget.$(OBJEXT)
|
||||
wesnoth_editor_OBJECTS = $(am_wesnoth_editor_OBJECTS)
|
||||
wesnoth_editor_LDADD = $(LDADD)
|
||||
wesnoth_editor_DEPENDENCIES =
|
||||
|
@ -497,6 +503,7 @@ am__depfiles_maybe = depfiles
|
|||
@AMDEP_TRUE@ ./$(DEPDIR)/editor_main.Po \
|
||||
@AMDEP_TRUE@ ./$(DEPDIR)/editor_palettes.Po \
|
||||
@AMDEP_TRUE@ ./$(DEPDIR)/editor_undo.Po ./$(DEPDIR)/events.Po \
|
||||
@AMDEP_TRUE@ ./$(DEPDIR)/file_chooser.Po \
|
||||
@AMDEP_TRUE@ ./$(DEPDIR)/filesystem.Po ./$(DEPDIR)/font.Po \
|
||||
@AMDEP_TRUE@ ./$(DEPDIR)/game.Po ./$(DEPDIR)/game_config.Po \
|
||||
@AMDEP_TRUE@ ./$(DEPDIR)/game_events.Po \
|
||||
|
@ -610,6 +617,7 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/editor_palettes.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/editor_undo.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/events.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_chooser.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filesystem.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/font.Po@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/game.Po@am__quote@
|
||||
|
@ -703,6 +711,28 @@ button.obj: widgets/button.cpp
|
|||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o button.obj `if test -f 'widgets/button.cpp'; then $(CYGPATH_W) 'widgets/button.cpp'; else $(CYGPATH_W) '$(srcdir)/widgets/button.cpp'; fi`
|
||||
|
||||
file_chooser.o: widgets/file_chooser.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_chooser.o -MD -MP -MF "$(DEPDIR)/file_chooser.Tpo" \
|
||||
@am__fastdepCXX_TRUE@ -c -o file_chooser.o `test -f 'widgets/file_chooser.cpp' || echo '$(srcdir)/'`widgets/file_chooser.cpp; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/file_chooser.Tpo" "$(DEPDIR)/file_chooser.Po"; \
|
||||
@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/file_chooser.Tpo"; exit 1; \
|
||||
@am__fastdepCXX_TRUE@ fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='widgets/file_chooser.cpp' object='file_chooser.o' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/file_chooser.Po' tmpdepfile='$(DEPDIR)/file_chooser.TPo' @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_chooser.o `test -f 'widgets/file_chooser.cpp' || echo '$(srcdir)/'`widgets/file_chooser.cpp
|
||||
|
||||
file_chooser.obj: widgets/file_chooser.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT file_chooser.obj -MD -MP -MF "$(DEPDIR)/file_chooser.Tpo" \
|
||||
@am__fastdepCXX_TRUE@ -c -o file_chooser.obj `if test -f 'widgets/file_chooser.cpp'; then $(CYGPATH_W) 'widgets/file_chooser.cpp'; else $(CYGPATH_W) '$(srcdir)/widgets/file_chooser.cpp'; fi`; \
|
||||
@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/file_chooser.Tpo" "$(DEPDIR)/file_chooser.Po"; \
|
||||
@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/file_chooser.Tpo"; exit 1; \
|
||||
@am__fastdepCXX_TRUE@ fi
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='widgets/file_chooser.cpp' object='file_chooser.obj' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/file_chooser.Po' tmpdepfile='$(DEPDIR)/file_chooser.TPo' @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o file_chooser.obj `if test -f 'widgets/file_chooser.cpp'; then $(CYGPATH_W) 'widgets/file_chooser.cpp'; else $(CYGPATH_W) '$(srcdir)/widgets/file_chooser.cpp'; fi`
|
||||
|
||||
combo.o: widgets/combo.cpp
|
||||
@am__fastdepCXX_TRUE@ if $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT combo.o -MD -MP -MF "$(DEPDIR)/combo.Tpo" \
|
||||
@am__fastdepCXX_TRUE@ -c -o combo.o `test -f 'widgets/combo.cpp' || echo '$(srcdir)/'`widgets/combo.cpp; \
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "util.hpp"
|
||||
#include "widgets/file_chooser.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
|
@ -262,4 +263,74 @@ void unit_speak(const config& message_info, display& disp, const unit_map& units
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
int show_file_chooser_dialog(display &disp, std::string &filename,
|
||||
const std::string title,
|
||||
int xloc, int yloc) {
|
||||
const events::event_context dialog_events_context;
|
||||
const gui::dialog_manager manager;
|
||||
const events::resize_lock prevent_resizing;
|
||||
|
||||
CVideo& screen = disp.video();
|
||||
SDL_Surface* const scr = screen.getSurface();
|
||||
SDL_Rect clipRect = disp.screen_area();
|
||||
|
||||
const int width = 400;
|
||||
const int height = 400;
|
||||
const int left_padding = 10;
|
||||
const int right_padding = 10;
|
||||
const int top_padding = 10;
|
||||
const int bot_padding = 10;
|
||||
|
||||
// If not both locations were supplied, put the dialog in the middle
|
||||
// of the screen.
|
||||
if (yloc <= -1 || xloc <= -1) {
|
||||
xloc = scr->w / 2 - width / 2;
|
||||
yloc = scr->h / 2 - height / 2;
|
||||
}
|
||||
std::vector<gui::button*> buttons_ptr;
|
||||
gui::button ok_button_(disp, string_table["ok_button"]);
|
||||
gui::button cancel_button_(disp, string_table["cancel_button"]);
|
||||
buttons_ptr.push_back(&ok_button_);
|
||||
buttons_ptr.push_back(&cancel_button_);
|
||||
surface_restorer restorer;
|
||||
gui::draw_dialog(xloc, yloc, width, height, disp, title, NULL, &buttons_ptr, &restorer);
|
||||
|
||||
gui::file_chooser fc(disp, filename);
|
||||
fc.set_location(xloc + left_padding, yloc + top_padding);
|
||||
fc.set_width(width - left_padding - right_padding);
|
||||
fc.set_height(height - top_padding - bot_padding);
|
||||
fc.set_dirty(true);
|
||||
|
||||
events::raise_draw_event();
|
||||
screen.flip();
|
||||
disp.invalidate_all();
|
||||
|
||||
CKey key;
|
||||
for (;;) {
|
||||
events::pump();
|
||||
events::raise_process_event();
|
||||
events::raise_draw_event();
|
||||
if (fc.choice_made()) {
|
||||
filename = fc.get_choice();
|
||||
return 0; // We know that the OK button is on index 0.
|
||||
}
|
||||
if (key[SDLK_ESCAPE]) {
|
||||
// Escape quits from the dialog.
|
||||
return -1;
|
||||
}
|
||||
for (std::vector<gui::button*>::iterator button_it = buttons_ptr.begin();
|
||||
button_it != buttons_ptr.end(); button_it++) {
|
||||
if ((*button_it)->pressed()) {
|
||||
// Return the index of the pressed button.
|
||||
filename = fc.get_choice();
|
||||
return button_it - buttons_ptr.begin();
|
||||
}
|
||||
}
|
||||
screen.flip();
|
||||
SDL_Delay(10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} //end namespace dialogs
|
||||
|
|
|
@ -49,6 +49,15 @@ std::string load_game_dialog(display& disp, bool* show_replay);
|
|||
|
||||
void unit_speak(const config& message_info, display& disp, const unit_map& units);
|
||||
|
||||
/// Show a dialog where the user can navigate through files and select a
|
||||
/// file. The filename is used as a starting point in the navigation and
|
||||
/// contains the chosen file when the function returns. Return the
|
||||
/// index of the button pressed, or -1 if the dialog was canceled
|
||||
/// through keypress.
|
||||
int show_file_chooser_dialog(display &displ, std::string &filename,
|
||||
const std::string title="Choose a File",
|
||||
int xloc=-1, int yloc=-1);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -213,13 +213,13 @@ void map_editor::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
|
|||
|
||||
|
||||
void map_editor::edit_save_as() {
|
||||
std::string input_name = get_dir(get_dir(get_user_data_dir() + "/editor") + "/maps/");
|
||||
const std::string default_dir =
|
||||
get_dir(get_dir(get_user_data_dir() + "/editor") + "/maps/");
|
||||
std::string input_name = filename_ == "" ? default_dir : filename_;
|
||||
int res = 0;
|
||||
int overwrite = 0;
|
||||
do {
|
||||
res = gui::show_dialog(gui_, NULL, "", "Save As ", gui::OK_CANCEL,
|
||||
NULL, NULL, "", &input_name);
|
||||
|
||||
res = dialogs::show_file_chooser_dialog(gui_, input_name, "Choose a File to Save As");
|
||||
if (res == 0) {
|
||||
if (file_exists(input_name)) {
|
||||
overwrite = gui::show_dialog(gui_, NULL, "Overwrite?",
|
||||
|
@ -291,8 +291,10 @@ void map_editor::edit_new_map() {
|
|||
}
|
||||
|
||||
void map_editor::edit_load_map() {
|
||||
const std::string fn = load_map_dialog(gui_);
|
||||
if (fn != "") {
|
||||
std::string fn = filename_ == "" ?
|
||||
get_dir(get_dir(get_user_data_dir() + "/editor") + "/maps/") : filename_;
|
||||
int res = dialogs::show_file_chooser_dialog(gui_, fn, "Choose a Map to Load");
|
||||
if (res == 0) {
|
||||
const std::string new_map = load_map(fn);
|
||||
if (new_map != "") {
|
||||
if (!changed_since_save() || confirm_modification_disposal(gui_)) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "../display.hpp"
|
||||
#include "../show_dialog.hpp"
|
||||
#include "../config.hpp"
|
||||
#include "../events.hpp"
|
||||
#include "../game_config.hpp"
|
||||
#include "../mapgen.hpp"
|
||||
#include "../filesystem.hpp"
|
||||
|
@ -529,3 +530,5 @@ FLIP_AXIS flip_dialog(display &disp) {
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ resize_dialog(display &disp, const unsigned curr_w, const unsigned curr_h);
|
|||
|
||||
FLIP_AXIS flip_dialog(display &disp);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
324
src/widgets/file_chooser.cpp
Normal file
324
src/widgets/file_chooser.cpp
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
|
||||
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "../font.hpp"
|
||||
#include "../events.hpp"
|
||||
#include "../display.hpp"
|
||||
#include "file_chooser.hpp"
|
||||
|
||||
namespace gui {
|
||||
|
||||
file_chooser::file_chooser(display &disp, std::string start_file)
|
||||
: widget(disp), disp_(disp), path_delim_('/'), current_dir_(get_path(start_file)),
|
||||
chosen_file_(start_file), file_list_(disp, files_in_current_dir_, false),
|
||||
filename_textbox_(disp, 100, start_file, true), choice_made_(false),
|
||||
last_selection_(-1) {
|
||||
// If the start file is not a file or directory, use the root.
|
||||
if (!file_exists(chosen_file_) || !is_directory(current_dir_)) {
|
||||
current_dir_ = path_delim_;
|
||||
chosen_file_ = current_dir_;
|
||||
}
|
||||
// Set sizes to some default values.
|
||||
set_location(1, 1);
|
||||
set_width(400);
|
||||
set_height(500);
|
||||
update_file_lists();
|
||||
}
|
||||
|
||||
void file_chooser::adjust_layout() {
|
||||
const int current_path_y = location().y;
|
||||
current_path_rect_.y = current_path_y;
|
||||
current_path_rect_.w = width();
|
||||
current_path_rect_.x = location().x;
|
||||
current_path_rect_.h = 18;
|
||||
const int file_list_y = current_path_y + current_path_rect_.h + 10;
|
||||
const int filename_textbox_y = location().y + height() - filename_textbox_.height();
|
||||
|
||||
const int file_list_height = filename_textbox_y - file_list_y - 10;
|
||||
|
||||
file_list_.set_width(width());
|
||||
filename_textbox_.set_width(width());
|
||||
|
||||
file_list_.set_loc(location().x, file_list_y);
|
||||
filename_textbox_.set_location(location().x, filename_textbox_y);
|
||||
|
||||
file_list_.set_max_height(file_list_height);
|
||||
// When the layout has changed we want to redisplay the files to
|
||||
// make them fit into the newly adjusted widget.
|
||||
set_dirty(true);
|
||||
}
|
||||
|
||||
void file_chooser::display_current_files() {
|
||||
bg_restore();
|
||||
std::vector<std::string> to_show;
|
||||
if (!is_root(current_dir_)) {
|
||||
to_show.push_back("..");
|
||||
}
|
||||
std::copy(dirs_in_current_dir_.begin(), dirs_in_current_dir_.end(),
|
||||
std::back_inserter(to_show));
|
||||
std::vector<std::string>::iterator it;
|
||||
for (it = to_show.begin(); it != to_show.end(); it++) {
|
||||
// Add a delimiter to show that these are directories.
|
||||
(*it) += path_delim_;
|
||||
}
|
||||
std::copy(files_in_current_dir_.begin(), files_in_current_dir_.end(),
|
||||
std::back_inserter(to_show));
|
||||
const int menu_font_size = 14; // Known from menu.cpp.
|
||||
for (it = to_show.begin(); it != to_show.end(); it++) {
|
||||
// Make sure that all lines fit.
|
||||
// Guess the width of the scrollbar to be 30 since it is not accessible from here.
|
||||
while (font::line_width(*it, menu_font_size) > file_list_.width() - 30) {
|
||||
(*it).resize((*it).size() - 1);
|
||||
}
|
||||
}
|
||||
file_list_.set_items(to_show);
|
||||
|
||||
// This will prevent the "box" with filenames from changing size on
|
||||
// every redisplay, it looks better when it's static.
|
||||
file_list_.set_width(width());
|
||||
}
|
||||
|
||||
void file_chooser::display_chosen_file() {
|
||||
// Clearing is not really necessary, but things end up nicer of we do.
|
||||
filename_textbox_.clear();
|
||||
if (is_directory(chosen_file_)) {
|
||||
filename_textbox_.set_text(strip_last_delim(chosen_file_) + path_delim_);
|
||||
}
|
||||
else {
|
||||
filename_textbox_.set_text(chosen_file_);
|
||||
}
|
||||
}
|
||||
|
||||
void file_chooser::draw() {
|
||||
if (!dirty()) {
|
||||
return;
|
||||
}
|
||||
display_current_files();
|
||||
display_chosen_file();
|
||||
font::draw_text(&disp_, current_path_rect_, 14, font::NORMAL_COLOUR,
|
||||
current_dir_, current_path_rect_.x, current_path_rect_.y,
|
||||
disp_.video().getSurface());
|
||||
set_dirty(false);
|
||||
}
|
||||
|
||||
void file_chooser::process() {
|
||||
CKey key;
|
||||
int mousex, mousey;
|
||||
const int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
|
||||
// The menu does not implement focus functionality, so we fake
|
||||
// it. We give the file list focus whenever the filename textbox
|
||||
// does not have focus. Inflexible but easy solution.
|
||||
if (!(mousex > location().x && (unsigned)mousex < location().x + width()
|
||||
&& mousey > location().y
|
||||
&& (unsigned)mousey < location().y + height() - filename_textbox_.height())) {
|
||||
// Hmm, as I understand it this should happen automatically when
|
||||
// the mouse is in the textbox again. However this is not the
|
||||
// case so this is done explicitly here.
|
||||
filename_textbox_.set_focus(true);
|
||||
}
|
||||
else {
|
||||
filename_textbox_.set_focus(false);
|
||||
}
|
||||
if (!filename_textbox_.focus()) {
|
||||
const bool new_left_button = mouse_flags&SDL_BUTTON_LMASK;
|
||||
|
||||
const bool new_up_arrow = key[SDLK_UP];
|
||||
const bool new_down_arrow = key[SDLK_DOWN];
|
||||
|
||||
const bool new_page_up = key[SDLK_PAGEUP];
|
||||
const bool new_page_down = key[SDLK_PAGEDOWN];
|
||||
file_list_.process(mousex, mousey, new_left_button, new_up_arrow,
|
||||
new_down_arrow, new_page_up, new_page_down, -1);
|
||||
const int new_selection = file_list_.selection();
|
||||
const bool double_click = file_list_.double_clicked();
|
||||
if (double_click && new_selection >= 0) {
|
||||
last_selection_ = new_selection;
|
||||
entry_chosen(new_selection);
|
||||
}
|
||||
if (new_selection >= 0 && last_selection_ != new_selection) {
|
||||
last_selection_ = new_selection;
|
||||
entry_selected(new_selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void file_chooser::entry_selected(const unsigned entry) {
|
||||
const int entry_index = entry - (is_root(current_dir_) ? 0 : 1);
|
||||
if (entry_index >= 0) {
|
||||
// Do not change the selection if the parent directory entry is selected.
|
||||
std::string selected;
|
||||
if ((unsigned)entry_index < dirs_in_current_dir_.size()) {
|
||||
const int dir_index = entry_index;
|
||||
selected = dirs_in_current_dir_[dir_index];
|
||||
}
|
||||
else {
|
||||
const int file_index = entry_index - dirs_in_current_dir_.size();
|
||||
selected = files_in_current_dir_[file_index];
|
||||
}
|
||||
chosen_file_ = add_path(current_dir_, selected);
|
||||
display_chosen_file();
|
||||
}
|
||||
}
|
||||
|
||||
/// Enter the directory or choose the file.
|
||||
void file_chooser::entry_chosen(const unsigned entry) {
|
||||
const int entry_index = entry - (is_root(current_dir_) ? 0 : 1);
|
||||
if (entry_index == -1) {
|
||||
// Parent dir wanted.
|
||||
if (!is_root(current_dir_)) {
|
||||
current_dir_ = get_path_up(current_dir_);
|
||||
update_file_lists();
|
||||
chosen_file_ = current_dir_;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((unsigned)entry_index < dirs_in_current_dir_.size()) {
|
||||
// Descend into a directory.
|
||||
const int dir_index = entry_index;
|
||||
const std::string selected_dir = dirs_in_current_dir_[dir_index];
|
||||
current_dir_ = add_path(current_dir_, selected_dir);
|
||||
chosen_file_ = current_dir_;
|
||||
update_file_lists();
|
||||
}
|
||||
else {
|
||||
// Choose a file.
|
||||
const int file_index = entry_index - dirs_in_current_dir_.size();
|
||||
const std::string selected_file = files_in_current_dir_[file_index];
|
||||
chosen_file_ = add_path(current_dir_, selected_file);
|
||||
choice_made_ = true;
|
||||
}
|
||||
}
|
||||
set_dirty(true);
|
||||
}
|
||||
|
||||
bool file_chooser::choice_made() const {
|
||||
return choice_made_;
|
||||
}
|
||||
|
||||
std::string file_chooser::get_choice() const {
|
||||
if (filename_textbox_.focus()) {
|
||||
return filename_textbox_.text();
|
||||
}
|
||||
return chosen_file_;
|
||||
}
|
||||
|
||||
void file_chooser::set_dirty(bool dirty) {
|
||||
widget::set_dirty(dirty);
|
||||
filename_textbox_.set_dirty(dirty);
|
||||
}
|
||||
|
||||
void file_chooser::set_location(const SDL_Rect& rect) {
|
||||
widget::set_location(rect);
|
||||
adjust_layout();
|
||||
}
|
||||
|
||||
void file_chooser::set_location(int x, int y) {
|
||||
widget::set_location(x, y);
|
||||
adjust_layout();
|
||||
}
|
||||
|
||||
void file_chooser::set_width(int w) {
|
||||
widget::set_width(w);
|
||||
adjust_layout();
|
||||
}
|
||||
|
||||
void file_chooser::set_height(int h) {
|
||||
widget::set_height(h);
|
||||
adjust_layout();
|
||||
}
|
||||
|
||||
std::string file_chooser::get_path(const std::string file_or_dir) const {
|
||||
std::string res_path = file_or_dir;
|
||||
if (!is_directory(file_or_dir)) {
|
||||
size_t index = file_or_dir.find_last_of(path_delim_);
|
||||
if (index != std::string::npos) {
|
||||
res_path = file_or_dir.substr(0, index);
|
||||
}
|
||||
}
|
||||
return res_path;
|
||||
}
|
||||
|
||||
std::string file_chooser::get_path_up(const std::string path, const unsigned levels) const {
|
||||
std::string curr_path = get_path(path);
|
||||
for (unsigned i = 0; i < levels; i++) {
|
||||
if (is_root(curr_path)) {
|
||||
break;
|
||||
}
|
||||
curr_path = strip_last_delim(curr_path);
|
||||
size_t index = curr_path.find_last_of(path_delim_);
|
||||
if (index != std::string::npos) {
|
||||
curr_path = curr_path.substr(0, index);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (curr_path.size() == 0) {
|
||||
// The root was reached, represent this as one delimiter only.
|
||||
curr_path = path_delim_;
|
||||
}
|
||||
return curr_path;
|
||||
}
|
||||
|
||||
std::string file_chooser::strip_last_delim(const std::string path) const {
|
||||
std::string res_string = path;
|
||||
if (path[path.size() - 1] == path_delim_) {
|
||||
res_string = path.substr(0, path.size() - 1);
|
||||
}
|
||||
return res_string;
|
||||
}
|
||||
|
||||
bool file_chooser::is_root(const std::string path) const {
|
||||
return path.size() == 0 || path.size() == 1 && path[0] == path_delim_;
|
||||
}
|
||||
|
||||
std::string file_chooser::add_path(const std::string path, const std::string to_add) {
|
||||
std::string joined_path = strip_last_delim(path);
|
||||
if (to_add.size() > 0) {
|
||||
if (to_add[0] == path_delim_) {
|
||||
joined_path += to_add;
|
||||
}
|
||||
else {
|
||||
joined_path += "/" + to_add;
|
||||
}
|
||||
}
|
||||
return joined_path;
|
||||
}
|
||||
|
||||
void file_chooser::update_file_lists() {
|
||||
files_in_current_dir_.clear();
|
||||
dirs_in_current_dir_.clear();
|
||||
get_files_in_dir(current_dir_, &files_in_current_dir_,
|
||||
&dirs_in_current_dir_, FILE_NAME_ONLY);
|
||||
}
|
||||
|
||||
void file_chooser::handle_event(const SDL_Event& event) {
|
||||
if (event.type == SDL_KEYDOWN) {
|
||||
if (event.key.keysym.sym == SDLK_RETURN) {
|
||||
if (filename_textbox_.focus()) {
|
||||
chosen_file_ = filename_textbox_.text();
|
||||
choice_made_ = true;
|
||||
}
|
||||
else {
|
||||
const int selected = file_list_.selection();
|
||||
if (selected >= 0) {
|
||||
entry_chosen(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
109
src/widgets/file_chooser.hpp
Normal file
109
src/widgets/file_chooser.hpp
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
|
||||
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef FILE_CHOOSER_H_INCLUDED
|
||||
#define FILE_CHOOSER_H_INCLUDED
|
||||
|
||||
#include "../display.hpp"
|
||||
#include "widget.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "textbox.hpp"
|
||||
#include "../filesystem.hpp"
|
||||
#include "../language.hpp"
|
||||
|
||||
|
||||
namespace gui {
|
||||
|
||||
/// A widget where the user may navigate through directories and choose
|
||||
/// a file.
|
||||
class file_chooser : public gui::widget {
|
||||
public:
|
||||
/// Initialize the file chooser. start_file is the file that will be
|
||||
/// selected when the dialog starts. The current directory will be
|
||||
/// the one the file is in.
|
||||
file_chooser(display &disp, std::string start_file="");
|
||||
|
||||
void draw();
|
||||
void process();
|
||||
|
||||
void set_dirty(bool dirty=true);
|
||||
|
||||
void set_location(const SDL_Rect& rect);
|
||||
void set_location(int x, int y);
|
||||
void set_width(int w);
|
||||
void set_height(int h);
|
||||
|
||||
/// Return true if the user is done making her choice.
|
||||
bool choice_made() const;
|
||||
|
||||
/// Return the choosen file.
|
||||
std::string get_choice() const;
|
||||
protected:
|
||||
virtual void handle_event(const SDL_Event& event);
|
||||
|
||||
private:
|
||||
/// If file_or_dir is a file, return the directory the file is in,
|
||||
/// if it is a directory, return the directory name. If no path
|
||||
/// delimiters could be found, return the unchanged argument.
|
||||
std::string get_path(const std::string file_or_dir) const;
|
||||
|
||||
/// Return the path that is the specified number of levels up from
|
||||
/// the path. If the movement could not proceed due to being at the
|
||||
/// root or having an invalid argument, return the path that the
|
||||
/// movement ended on.
|
||||
std::string get_path_up(const std::string path,
|
||||
const unsigned levels=1) const;
|
||||
|
||||
/// Return path with to_add added, using a path delimiter between them.
|
||||
std::string add_path(const std::string path, const std::string to_add);
|
||||
|
||||
/// Return the string with the last path delimiter removed, if one
|
||||
/// was there.
|
||||
std::string strip_last_delim(const std::string path) const;
|
||||
|
||||
/// Return true if the path is the root of the filesystem.
|
||||
bool is_root(const std::string path) const;
|
||||
|
||||
/// Adjust the layout of the widget.
|
||||
void adjust_layout();
|
||||
|
||||
/// Show the files in the current directory.
|
||||
void display_current_files();
|
||||
|
||||
/// Display the currently selected file in the file text box.
|
||||
void display_chosen_file();
|
||||
|
||||
/// Updated the locally maintained lists of files and directories in
|
||||
/// the current directory.
|
||||
void update_file_lists();
|
||||
|
||||
/// Set the textbox to reflect the selected file.
|
||||
void entry_selected(const unsigned entry);
|
||||
|
||||
/// Enter the directory or choose the file.
|
||||
void entry_chosen(const unsigned entry);
|
||||
|
||||
display &disp_;
|
||||
const char path_delim_;
|
||||
std::string current_dir_;
|
||||
std::string chosen_file_;
|
||||
std::vector<std::string> files_in_current_dir_, dirs_in_current_dir_;
|
||||
menu file_list_;
|
||||
textbox filename_textbox_;
|
||||
SDL_Rect current_path_rect_;
|
||||
bool choice_made_;
|
||||
int last_selection_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FILE_CHOOSER_H_INCLUDED
|
|
@ -25,7 +25,9 @@ menu::menu(display& disp, const std::vector<std::string>& items,
|
|||
uparrow_(disp,"",gui::button::TYPE_PRESS,"uparrow-button"),
|
||||
downarrow_(disp,"",gui::button::TYPE_PRESS,"downarrow-button"),
|
||||
scrollbar_(disp,this), scrollbar_height_(0),
|
||||
double_clicked_(false), num_selects_(true)
|
||||
double_clicked_(false), num_selects_(true),
|
||||
ignore_next_doubleclick_(false),
|
||||
last_was_doubleclick_(false)
|
||||
{
|
||||
for(std::vector<std::string>::const_iterator item = items.begin();
|
||||
item != items.end(); ++item) {
|
||||
|
@ -59,6 +61,8 @@ void menu::set_scrollbar_height()
|
|||
if (scrollbar_height_ > height()) {
|
||||
std::cerr << "Strange. For some reason I want my scrollbar" <<
|
||||
" to be larger than me!\n\n";
|
||||
std::cerr << "pos_percent=" << pos_percent << " height()=" << height()
|
||||
<< std::endl;
|
||||
scrollbar_height_ = height() - buttons_height;
|
||||
}
|
||||
|
||||
|
@ -162,6 +166,47 @@ void menu::erase_item(size_t index)
|
|||
}
|
||||
}
|
||||
|
||||
void menu::set_items(const std::vector<std::string>& items) {
|
||||
items_.clear();
|
||||
itemRects_.clear();
|
||||
column_widths_.clear();
|
||||
undrawn_items_.clear();
|
||||
height_ = -1; // Force recalculation of the height.
|
||||
width_ = -1; // Force recalculation of the width.
|
||||
max_items_ = -1; // Force recalculation of the max items.
|
||||
// Scrollbar and buttons will be reanabled if they are needed.
|
||||
scrollbar_.enable(false);
|
||||
uparrow_.hide(true);
|
||||
downarrow_.hide(true);
|
||||
first_item_on_screen_ = 0;
|
||||
selected_ = click_selects_ ? -1:0;
|
||||
for (std::vector<std::string>::const_iterator item = items.begin();
|
||||
item != items.end(); ++item) {
|
||||
items_.push_back(config::quoted_split(*item,',',false));
|
||||
|
||||
//make sure there is always at least one item
|
||||
if(items_.back().empty())
|
||||
items_.back().push_back(" ");
|
||||
|
||||
//if the first character in an item is an asterisk,
|
||||
//it means this item should be selected by default
|
||||
std::string& first_item = items_.back().front();
|
||||
if(first_item.empty() == false && first_item[0] == '*') {
|
||||
selected_ = items_.size()-1;
|
||||
first_item.erase(first_item.begin());
|
||||
}
|
||||
}
|
||||
set_loc(x_, y_); // Force some more updating.
|
||||
calculate_position();
|
||||
drawn_ = false;
|
||||
}
|
||||
|
||||
void menu::set_max_height(const int new_max_height) {
|
||||
max_height_ = new_max_height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t menu::max_items_onscreen() const
|
||||
{
|
||||
if(max_items_ != -1) {
|
||||
|
@ -300,7 +345,25 @@ void menu::handle_event(const SDL_Event& event)
|
|||
}
|
||||
|
||||
if(event.type == DOUBLE_CLICK_EVENT) {
|
||||
double_clicked_ = true;
|
||||
if (ignore_next_doubleclick_) {
|
||||
ignore_next_doubleclick_ = false;
|
||||
}
|
||||
else {
|
||||
double_clicked_ = true;
|
||||
last_was_doubleclick_ = true;
|
||||
}
|
||||
}
|
||||
else if (last_was_doubleclick_) {
|
||||
// If we have a double click as the next event, it means
|
||||
// this double click was generated from a click that
|
||||
// already has helped in generating a double click.
|
||||
SDL_Event ev;
|
||||
SDL_PeepEvents(&ev, 1, SDL_PEEKEVENT,
|
||||
SDL_EVENTMASK(DOUBLE_CLICK_EVENT));
|
||||
if (ev.type == DOUBLE_CLICK_EVENT) {
|
||||
ignore_next_doubleclick_ = true;
|
||||
}
|
||||
last_was_doubleclick_ = false;
|
||||
}
|
||||
}
|
||||
} else if(event.type == SDL_MOUSEMOTION && click_selects_) {
|
||||
|
@ -408,6 +471,7 @@ int menu::process(int x, int y, bool button,bool up_arrow,bool down_arrow,
|
|||
}
|
||||
|
||||
if(show_result_) {
|
||||
show_result_ = false;
|
||||
return selected_;
|
||||
} else {
|
||||
return -1;
|
||||
|
@ -419,9 +483,11 @@ bool menu::show_scrollbar() const
|
|||
return items_.size() > max_items_onscreen();
|
||||
}
|
||||
|
||||
bool menu::double_clicked() const
|
||||
bool menu::double_clicked()
|
||||
{
|
||||
return double_clicked_;
|
||||
bool old = double_clicked_;
|
||||
double_clicked_ = false;
|
||||
return old;
|
||||
}
|
||||
|
||||
void menu::set_numeric_keypress_selection(bool value)
|
||||
|
|
|
@ -36,12 +36,19 @@ public:
|
|||
|
||||
void erase_item(size_t index);
|
||||
|
||||
void set_items(const std::vector<std::string>& items);
|
||||
|
||||
/// Set a new max height for this menu. Note that this does not take
|
||||
/// effect immideately, only after certain operations that clear
|
||||
/// everything, such as set_items().
|
||||
void set_max_height(const int new_max_height);
|
||||
|
||||
size_t nitems() const { return items_.size(); }
|
||||
|
||||
int process(int x, int y, bool button,bool up_arrow,bool down_arrow,
|
||||
bool page_up, bool page_down, int select_item=-1);
|
||||
|
||||
bool double_clicked() const;
|
||||
bool double_clicked();
|
||||
|
||||
void set_numeric_keypress_selection(bool value);
|
||||
|
||||
|
@ -109,6 +116,11 @@ private:
|
|||
///variable which determines whether a numeric keypress should
|
||||
///select an item on the dialog
|
||||
bool num_selects_;
|
||||
// These two variables are used to get the correct double click
|
||||
// behavior so that a click that causes one double click wont be
|
||||
// counted as a first click in the "next" double click.
|
||||
bool ignore_next_doubleclick_;
|
||||
bool last_was_doubleclick_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue