description text.
#include "geomdraw.h"
static Exhibit *create_exhibit(const char *type);
+static void clean_desc_text(char *dest, const char *src);
ExhibitSlot::ExhibitSlot(Exhibit *ex)
ExData exd;
if(desc) {
- exd.text = std::string(desc);
+ char *fixed_desc = new char[strlen(desc) + 1];
+ clean_desc_text(fixed_desc, desc);
+ exd.text = std::string(fixed_desc);
+ delete [] fixed_desc;
}
if(voice) {
exd.voice = new OggVorbisStream;
error_log("unknown exhibit type: %s\n", type);
return 0;
}
+
+/* clean up description text to be more easily layed out later.
+ * more specifically:
+ * - remove redundant spaces
+ * - remove all newlines except as paragraph separators
+ * - remove all other whitespace chars
+ * destination buffer must be as large as the source buffer
+ */
+static void clean_desc_text(char *dest, const char *src)
+{
+ while(*src) {
+ if(isspace(*src)) {
+ if(*src == '\n' && *(src + 1) == '\n') {
+ *dest++ = '\n';
+ } else {
+ *dest++ = ' ';
+ }
+ while(*src && isspace(*src)) ++src;
+ } else {
+ *dest++ = *src++;
+ }
+ }
+ *dest = 0;
+}
static long timeout = 2000;
static long trans_time = 250;
-static dtx_font *font;
+dtx_font *ui_font;
+int ui_font_size = FONTSZ;
void set_message_timeout(long tm)
{
void draw_ui()
{
- if(!font) return;
+ if(!ui_font) return;
while(msglist && msglist->show_until <= time_msec) {
Message *msg = msglist;
delete msg;
}
- dtx_use_font(font, FONTSZ);
+ dtx_use_font(ui_font, ui_font_size);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
done_init = true;
- if(!(font = dtx_open_font("data/ui.font", 0))) {
+ if(!(ui_font = dtx_open_font("data/ui.font", 0))) {
fprintf(stderr, "failed to open font: data/ui.font\n");
return false;
}
- dtx_prepare_range(font, FONTSZ, 32, 127);
+ dtx_prepare_range(ui_font, ui_font_size, 32, 127);
return true;
}
#include <stdarg.h>
#include <gmath/gmath.h>
+struct dtx_font;
+extern dtx_font *ui_font;
+extern int ui_font_size;
+
void set_message_timeout(long timeout);
void show_message(const char *fmt, ...);
void show_message(long timeout, const Vec3 &color, const char *fmt, ...);
#include "ui_exhibit.h"
+#include "ui.h"
#include "app.h"
+#include <drawtext.h>
+
+static void draw_titlebar();
+static void draw_tabs();
+static void layout_text(const char *text);
+
+static Vec3 pos;
+static Vec2 size;
+static float text_padding;
+static Exhibit *ex;
+static int vis_tab;
+static float scroll;
+static std::vector<const char*> text_lines;
+static AudioStream *voice;
+
bool exui_init()
{
+ size.x = 150;
+ size.y = 180;
+ text_padding = size.x * 0.01;
+
return true;
}
{
}
+void exui_change_tab(int dir)
+{
+}
+
+void exui_scroll(float delta)
+{
+}
+
+bool exui_raycast(const Ray &ray)
+{
+ return false;
+}
+
void exui_update(float dt)
{
+ if(exsel_active.ex != ex) {
+ ex = exsel_active.ex;
+ scroll = 0.0f;
+ vis_tab = 0;
+ text_lines.clear();
+ if(voice) voice->stop();
+
+ if(ex) {
+ int num_data = ex->data.size();
+ for(int i=0; i<num_data; i++) {
+ if(ex->data[i].type == EXDATA_INFO) {
+ layout_text(ex->data[i].text.c_str());
+ voice = ex->data[i].voice;
+ }
+ }
+
+ if(voice) {
+ voice->play(AUDIO_PLAYMODE_ONCE);
+ }
+ } else {
+ voice = 0;
+ }
+ }
}
void exui_draw()
{
if(!exsel_active) return;
+ draw_titlebar();
+ draw_tabs();
+}
+
+static void draw_titlebar()
+{
+}
+
+static void draw_tabs()
+{
+}
+
+static void layout_text(const char *text)
+{
+ text_lines.clear();
+ if(!text) return;
+ if(!ui_font) return;
+
+ dtx_use_font(ui_font, ui_font_size);
+
+ float pos = text_padding;
+ text_lines.push_back(text);
+ const char *last_break = 0;
+
+ while(*text) {
+ if(*text == '\n') { // paragraph break
+ text_lines.push_back(text);
+ text_lines.push_back(++text);
+ pos = text_padding;
+ last_break = 0;
+ continue;
+ }
+
+ int code = dtx_utf8_char_code(text);
+ const char *next = dtx_utf8_next_char((char*)text);
+ pos += dtx_glyph_width(code);
+
+ if(pos >= size.x - text_padding) {
+ if(text == text_lines.back()) {
+ // not even a single character fits on a line... abort
+ warning_log("text layout failed. glyph %d doesn't fit in line (%g)\n", code, size.x - 2.0 * text_padding);
+ text_lines.clear();
+ return;
+ }
+ if(last_break) {
+ text_lines.push_back(last_break + 1);
+ last_break = 0;
+ } else {
+ // no good point to break, just break here
+ text_lines.push_back(text);
+ }
+ pos = text_padding;
+ }
+ text = next;
+ }
}
#ifndef UI_EXHIBIT_H_
#define UI_EXHIBIT_H_
+#include <gmath/gmath.h>
+
bool exui_init();
void exui_shutdown();
+void exui_change_tab(int dir);
+void exui_scroll(float delta);
+
+bool exui_raytest(const Ray &ray);
+
void exui_update(float dt);
void exui_draw();