Here's a first attempt at a patch for the back button for story screens:
http://wiki.wesnoth.org/Good_Ideas
http://www.wesnoth.org/forum/viewtopic.php?t=8857
There is already a patch in the tracker for this:
https://gna.org/patch/?1536
However I didn't realise someone had started when I wrote this, and
this is rather further along than that one is.
Problems with that patch:
* Back doesn't work properly (try it on the last page of the intro
where it shows you the map) - can't go back.
* Doesn't wire up back button in all the situations next button is clickable.
* Probably violates screen size in USE_TINY_GUI mode
* There's no key shortcut for back.
Features this patch has:
* Handles back properly so that you can go all the way back to the
start from the end.
* Handles skip properly so that all segments are skipped not just per
segment (but can still go back so this is ok!)
* Adds functional quit button.
* Adds key controls: RIGHT is added for next, LEFT and BACKSPACE for back.
Improves the implementation:
* no longer throws quit exception to quit (was just caught and
suppressed anyway).
* play story segments from either end so that back can work properly.
* adds reverse direction iteration for config::const_child_iterator (was needed)
Index: src/storyscreen/render.cpp
===================================================================
--- src/storyscreen/render.cpp (revision 41922)
+++ src/storyscreen/render.cpp (working copy)
@@ -81,13 +81,17 @@
namespace storyscreen {
-part_ui::part_ui(part& p, display& disp, gui::button& next_button, gui::button& skip_button)
+part_ui::part_ui(part& p, display& disp,
+ gui::button& next_button, gui::button& back_button,
+ gui::button& skip_button, gui::button& quit_button)
: p_(p)
, disp_(disp)
, video_(disp.video())
, keys_()
, next_button_(next_button)
+ , back_button_(back_button)
, skip_button_(skip_button)
+ , quit_button_(quit_button)
, ret_(NEXT)
, scale_factor_(1.0)
, base_rect_()
@@ -139,8 +143,10 @@
buttons_x_ = video_.getx() - 50;
buttons_y_ = base_rect_.y + base_rect_.h - 20;
- next_button_.set_location(buttons_x_, buttons_y_ - 20);
- skip_button_.set_location(buttons_x_, buttons_y_);
+ next_button_.set_location(buttons_x_, buttons_y_ - 60);
+ back_button_.set_location(buttons_x_, buttons_y_ - 40);
+ skip_button_.set_location(buttons_x_, buttons_y_ - 20);
+ quit_button_.set_location(buttons_x_, buttons_y_);
#else // elif !defined(USE_TINY_GUI)
@@ -163,12 +169,16 @@
buttons_y_ = video_.gety() - 40;
break;
}
- next_button_.set_location(buttons_x_, buttons_y_ - 30);
- skip_button_.set_location(buttons_x_, buttons_y_);
+ next_button_.set_location(buttons_x_, buttons_y_ - 90);
+ back_button_.set_location(buttons_x_, buttons_y_ - 60);
+ skip_button_.set_location(buttons_x_, buttons_y_ - 30);
+ quit_button_.set_location(buttons_x_, buttons_y_);
#endif
next_button_.set_volatile(true);
+ back_button_.set_volatile(true);
skip_button_.set_volatile(true);
+ quit_button_.set_volatile(true);
}
void part_ui::prepare_floating_images()
@@ -210,10 +220,18 @@
ret_ = SKIP;
return false;
}
+ else if(quit_button_.pressed()) {
+ ret_ = QUIT;
+ return false;
+ }
else if(next_button_.pressed()) {
ret_ = NEXT;
return false;
}
+ else if(back_button_.pressed()) {
+ ret_ = BACK;
+ return false;
+ }
disp_.delay(fi.display_delay() / 50);
@@ -238,7 +256,9 @@
}
}
- if(keys_[SDLK_ESCAPE] || next_button_.pressed() || skip_button_.pressed()) {
+ if(keys_[SDLK_ESCAPE] ||
+ next_button_.pressed() || back_button_.pressed() ||
+ skip_button_.pressed() || quit_button_.pressed()) {
skip = true;
++fi_n;
continue;
@@ -429,10 +449,10 @@
// by the buttons being hidden and unhidden in this scope.
update_locker locker(video_);
- //back_button_.hide();
next_button_.hide();
+ back_button_.hide();
skip_button_.hide();
- //quit_button_.hide();
+ quit_button_.hide();
#ifndef LOW_MEM
blur_area(video_, fix_text_y, fix_text_h);
@@ -450,8 +470,12 @@
// Make GUI1 buttons aware of background modifications
next_button_.set_location(next_button_.location());
next_button_.hide(false);
+ back_button_.set_location(back_button_.location());
+ back_button_.hide(false);
skip_button_.set_location(skip_button_.location());
skip_button_.hide(false);
+ quit_button_.set_location(quit_button_.location());
+ quit_button_.hide(false);
}
if(imgs_.empty()) {
@@ -479,9 +503,9 @@
++scan.y;
}
- const bool keydown = keys_[SDLK_SPACE] || keys_[SDLK_RETURN] || keys_[SDLK_KP_ENTER];
+ const bool next_keydown = keys_[SDLK_SPACE] || keys_[SDLK_RETURN] || keys_[SDLK_KP_ENTER] || keys_[SDLK_RIGHT];
- if((keydown && !last_key) || next_button_.pressed()) {
+ if((next_keydown && !last_key) || next_button_.pressed()) {
if(skip == true || scan_finished) {
ret_ = NEXT;
break;
@@ -490,11 +514,22 @@
}
}
- last_key = keydown;
+ const bool back_keydown = keys_[SDLK_BACKSPACE] || keys_[SDLK_LEFT];
+ if((back_keydown && !last_key) || back_button_.pressed()) {
+ ret_ = BACK;
+ break;
+ }
+
+ last_key = next_keydown || back_keydown;
+
if(keys_[SDLK_ESCAPE] || skip_button_.pressed()) {
ret_ = SKIP;
return;
+ }
+ else if(quit_button_.pressed()) {
+ ret_ = QUIT;
+ return;
}
events::pump();
@@ -517,20 +552,32 @@
{
bool last_key = true;
while(true) {
- const bool keydown = keys_[SDLK_SPACE] || keys_[SDLK_RETURN] || keys_[SDLK_KP_ENTER];
+ const bool next_keydown = keys_[SDLK_SPACE] || keys_[SDLK_RETURN] || keys_[SDLK_KP_ENTER] || keys_[SDLK_RIGHT];
- if((keydown && !last_key) || next_button_.pressed()) {
+ if((next_keydown && !last_key) || next_button_.pressed()) {
ret_ = NEXT;
break;
}
- last_key = keydown;
+ const bool back_keydown = keys_[SDLK_BACKSPACE] || keys_[SDLK_LEFT];
+ if((back_keydown && !last_key) || back_button_.pressed()) {
+ ret_ = BACK;
+ break;
+ }
+
+ last_key = next_keydown || back_keydown;
+
if(keys_[SDLK_ESCAPE] || skip_button_.pressed()) {
ret_ = SKIP;
return;
}
+ if(quit_button_.pressed()) {
+ ret_ = QUIT;
+ return;
+ }
+
events::pump();
events::raise_process_event();
events::raise_draw_event();
Index: src/storyscreen/interface.cpp
===================================================================
--- src/storyscreen/interface.cpp (revision 41922)
+++ src/storyscreen/interface.cpp (working copy)
@@ -47,20 +47,19 @@
}
} // end anonymous namespace
-void show_storyscreen(display& disp, const vconfig& story_cfg, const std::string& scenario_name)
+storyscreen::STORY_RESULT show_storyscreen(display& disp, const vconfig& story_cfg,
+ const std::string& scenario_name,
+ storyscreen::START_POSITION startpos)
{
LOG_NG << "entering storyscreen procedure...\n";
storyscreen::controller ctl(disp, story_cfg, scenario_name);
- try {
- ctl.show();
- } catch(storyscreen::controller::quit const&) {
- LOG_NG << "leaving storyscreen for titlescreen...\n";
- STUB();
- }
+ storyscreen::STORY_RESULT ret = ctl.show(startpos);
LOG_NG << "leaving storyscreen procedure...\n";
+
+ return ret;
}
void show_endscreen(display& /*disp*/, const t_string& /*text*/, unsigned int /*duration*/)
Index: src/storyscreen/controller.cpp
===================================================================
--- src/storyscreen/controller.cpp (revision 41922)
+++ src/storyscreen/controller.cpp (working copy)
@@ -118,17 +118,17 @@
}
}
-void controller::show()
+STORY_RESULT controller::show(START_POSITION startpos)
{
if(parts_.empty()) {
LOG_NG << "no storyscreen parts to show\n";
- return;
+ return NEXT;
}
gui::button next_button(disp_.video(),_("Next") + std::string(" >"));
+ gui::button back_button(disp_.video(),std::string("< ")+_("Back"));
gui::button skip_button(disp_.video(),_("Skip"));
- // TODO:
- // gui::button back_button(disp_.video(),std::string("< ")+_("Next"));
+ gui::button quit_button(disp_.video(),_("Quit"));
// Build renderer cache unless built for a low-memory environment;
// caching the scaled backgrounds can take over a decent amount of memory.
@@ -136,18 +136,28 @@
std::vector< render_pointer_type > uis_;
foreach(part_pointer_type p, parts_) {
ASSERT_LOG( p != NULL, "Ouch: hit NULL storyscreen part in collection" );
- render_pointer_type const rpt(new part_ui(*p, disp_, next_button, skip_button));
+ render_pointer_type const rpt(new part_ui(*p, disp_, next_button, back_button, skip_button, quit_button));
uis_.push_back(rpt);
}
#endif
size_t k = 0;
+ switch(startpos) {
+ case START_BEGINNING:
+ break;
+ case START_END:
+ k = parts_.size() -1;
+ break;
+ default:
+ assert(false);
+ break;
+ }
while(k < parts_.size()) {
#ifndef LOW_MEM
render_reference_type render_interface = *uis_[k];
#else
- render_value_type render_interface(*parts_[k], disp_, next_button, skip_button);
+ render_value_type render_interface(*parts_[k], disp_, next_button, back_button, skip_button, quit_button);
#endif
LOG_NG << "displaying storyscreen part " << k+1 << " of " << parts_.size() << '\n';
@@ -157,18 +167,23 @@
++k;
break;
case part_ui::BACK:
- // If we are at the first page we can't go back.
if(k > 0) {
--k;
+ }
+ else {
+ return BACK;
}
break;
case part_ui::SKIP:
- k = parts_.size();
- break;
+ return SKIP;
+ case part_ui::QUIT:
+ return QUIT;
default:
- throw quit();
+ assert(false);
+ return QUIT;
}
}
+ return NEXT;
}
} // end namespace storyscreen
Index: src/storyscreen/render.hpp
===================================================================
--- src/storyscreen/render.hpp (revision 41922)
+++ src/storyscreen/render.hpp (working copy)
@@ -45,9 +45,9 @@
/** Storyscreen result. */
enum RESULT {
NEXT, /**< The user pressed the go-next button. */
- BACK, /**< The user pressed the go-back button (TODO: not implemented). */
+ BACK, /**< The user pressed the go-back button. */
SKIP, /**< The user pressed the skip button. */
- QUIT /**< The user pressed the quit button (TODO: not implemented). */
+ QUIT /**< The user pressed the quit button. */
};
/**
@@ -57,7 +57,9 @@
* @param next_button Next button. Shouldn't be destroyed before the part_ui object.
* @param skip_button Skip button. Shouldn't be destroyed before the part_ui object.
*/
- part_ui(part& p, display& disp, gui::button& next_button, gui::button& skip_button);
+ part_ui(part& p, display& disp,
+ gui::button& next_button, gui::button& back_button,
+ gui::button& skip_button, gui::button& quit_button);
/**
* Render and display the storyscreen, process and return user input.
@@ -70,10 +72,10 @@
CVideo& video_; // convenience, it's currently obtained from disp_
CKey keys_; // convenience
- //gui::button& back_button_;
gui::button& next_button_;
+ gui::button& back_button_;
gui::button& skip_button_;
- //gui::button& quit_button_;
+ gui::button& quit_button_;
RESULT ret_;
Index: src/storyscreen/interface.hpp
===================================================================
--- src/storyscreen/interface.hpp (revision 41922)
+++ src/storyscreen/interface.hpp (working copy)
@@ -27,6 +27,22 @@
#include <string>
+namespace storyscreen {
+
+enum STORY_RESULT {
+ NEXT,
+ BACK,
+ SKIP,
+ QUIT
+};
+
+enum START_POSITION {
+ START_BEGINNING,
+ START_END
+};
+
+} /* storyscreen namespace */
+
/**
* Function to show an introduction sequence using story WML.
* The WML config data (story_cfg) has a format similar to:
@@ -41,8 +57,11 @@
* storyline,and 'img' is a background image. Each part of the sequence will
* be displayed in turn, with the user able to go to the next part, or skip
* it entirely.
+ * @return is NEXT if the story played to the end, BACK if the story played to the beginning, and QUIT if the story was quit
*/
-void show_storyscreen(display& disp, const vconfig& story_cfg, const std::string& scenario_name);
+storyscreen::STORY_RESULT show_storyscreen(display& disp, const vconfig& story_cfg,
+ const std::string& scenario_name,
+ storyscreen::START_POSITION startpos);
/**
* Displays a simple fading screen with any user-provided text.
Index: src/storyscreen/controller.hpp
===================================================================
--- src/storyscreen/controller.hpp (revision 41922)
+++ src/storyscreen/controller.hpp (working copy)
@@ -21,6 +21,7 @@
#define STORYSCREEN_CONTROLLER_HPP_INCLUDED
#include "events.hpp"
+#include "interface.hpp"
#include "variable.hpp"
#include "video.hpp"
@@ -44,7 +45,7 @@
/**
* Display all story screen parts in a first..last sequence.
*/
- void show();
+ STORY_RESULT show(START_POSITION startpos=START_BEGINNING);
private:
typedef boost::shared_ptr< part > part_pointer_type;
@@ -73,8 +74,6 @@
public:
struct no_parts {};
- struct quit {};
-
};
} // end namespace storyscreen
Index: src/playsingle_controller.cpp
===================================================================
--- src/playsingle_controller.cpp (revision 41922)
+++ src/playsingle_controller.cpp (working copy)
@@ -286,8 +286,35 @@
sound::commit_music_changes();
if(!skip_replay) {
- foreach (const config &s, story) {
- show_storyscreen(*gui_, vconfig(s, true), level_["name"]);
+ config::const_child_iterator itor = story.first;
+ storyscreen::START_POSITION startpos = storyscreen::START_BEGINNING;
+ while(itor != story.second) {
+ storyscreen::STORY_RESULT result = show_storyscreen(*gui_, vconfig(*itor, true), level_["name"], startpos);
+ switch(result) {
+ case storyscreen::NEXT:
+ if(itor != story.second) {
+ ++itor;
+ startpos = storyscreen::START_BEGINNING;
+ }
+ break;
+ case storyscreen::BACK:
+ if(itor != story.first) {
+ --itor;
+ startpos = storyscreen::START_END;
+ }
+ break;
+ case storyscreen::SKIP:
+ itor = story.second;
+ --itor;
+ startpos = storyscreen::START_END;
+ break;
+ case storyscreen::QUIT:
+ return QUIT;
+ default:
+ assert(false);
+ itor = story.second;
+ break;
+ }
}
}
gui_->labels().read(level_);
Index: src/config.hpp
===================================================================
--- src/config.hpp (revision 41922)
+++ src/config.hpp (working copy)
@@ -131,6 +131,8 @@
const_child_iterator &operator++() { ++i_; return *this; }
const_child_iterator operator++(int) { return const_child_iterator(i_++); }
+ const_child_iterator &operator--() { --i_; return *this; }
+ const_child_iterator operator--(int) { return const_child_iterator(i_--); }
const config &operator*() const { return **i_; }
const config *operator->() const { return &**i_; }
Index: changelog
===================================================================
--- changelog (revision 41922)
+++ changelog (working copy)
@@ -26,6 +26,7 @@
* Fixed picking the proper locale, the problem only occurred on some
systems
* Added a way to compile wesnoth on windows by using CMake + MSVC9.
+ * Added back and quit buttons to the story screens.
Version 1.8.0:
* AI:
_______________________________________________
Wesnoth-dev mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-dev