void TBInlineSelect::SetValueInternal(double value, bool update_text)
{
    value = CLAMP(value, m_min, m_max);
    if (value == m_value)
        return;
    m_value = value;

    if (update_text)
    {
        TBStr strval;

        double prec = m_value - floor(m_value);
        if (prec < .001)
        {
            strval.SetFormatted("%.0f", m_value);
        }
        else
            strval.SetFormatted("%.2f", m_value);


        m_editfield.SetText(strval);
    }

    TBWidgetEvent ev(EVENT_TYPE_CHANGED);
    InvokeEvent(ev);

    // Warning: Do nothing here since the event might have deleted us.
    //          If needed, check if we are alive using a safe pointer first.
}
예제 #2
0
bool ScrollContainerWindow::OnEvent(const TBWidgetEvent &ev)
{
	if (ev.type == EVENT_TYPE_CLICK)
	{
		if (ev.target->GetID() == TBIDC("add img"))
		{
			TBButton *button = TBSafeCast<TBButton>(ev.target);
			TBSkinImage *skin_image = new TBSkinImage;
			skin_image->SetSkinBg(TBIDC("Icon16"));
			button->GetContentRoot()->AddChild(skin_image, WIDGET_Z_BOTTOM);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("new buttons"))
		{
			for(int i = 0; i < ev.target->data.GetInt(); i++)
			{
				TBStr str;
				str.SetFormatted("Remove %d", i);
				TBButton *button = new TBButton;
				button->SetID(TBIDC("remove button"));
				button->SetText(str);
				ev.target->GetParent()->AddChild(button);
			}
			return true;
		}
		else if (ev.target->GetID() == TBIDC("new buttons delayed"))
		{
			for(int i = 0; i < ev.target->data.GetInt(); i++)
			{
				TBMessageData *data = new TBMessageData();
				data->id1 = ev.target->GetParent()->GetID();
				data->v1.SetInt(i);
				PostMessageDelayed(TBIDC("new button"), data, 100 + i * 500);
			}
			return true;
		}
		else if (ev.target->GetID() == TBIDC("remove button"))
		{
			ev.target->GetParent()->RemoveChild(ev.target);
			delete ev.target;
			return true;
		}
		else if (ev.target->GetID() == TBIDC("showpopupmenu1"))
		{
			if (TBMenuWindow *menu = new TBMenuWindow(ev.target, TBIDC("popupmenu1")))
				menu->Show(&popup_menu_source, TBPopupAlignment());
			return true;
		}
		else if (ev.target->GetID() == TBIDC("popupmenu1"))
		{
			TBStr str;
			str.SetFormatted("Menu event received!\nref_id: %d", (int)ev.ref_id);
			TBMessageWindow *msg_win = new TBMessageWindow(this, TBIDC("popup_dialog"));
			msg_win->Show("Info", str);
			return true;
		}
	}
	return DemoWindow::OnEvent(ev);
}
예제 #3
0
파일: App.cpp 프로젝트: BibleUs/turbobadger
void Render()
{
	// ... any gl code goes here ...
	// We have a background skin on root, so we don't need to clear the screen.
	// glViewport(0, 0, g_Width, g_Height);
	// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	g_renderer->BeginPaint(root->GetRect().w, root->GetRect().h);

	root->InvokePaint(TBWidget::PaintProps());

	static int fps = 0;
	static uint32 frame_counter = 0;
	static double frame_counter_reset_time = TBSystem::GetTimeMS();

	frame_counter++;

	// Update the FPS counter
	double time = TBSystem::GetTimeMS();
	if (time > frame_counter_reset_time + 1000)
	{
		fps = (int) ((frame_counter / (time - frame_counter_reset_time)) * 1000);
		frame_counter_reset_time = time;
		frame_counter = 0;
	}

	// Draw FPS
	TBStr str;
	str.SetFormatted("FPS: %d", fps);
	root->GetFont()->DrawString(5, 5, TBColor(255, 255, 255), str);

	g_renderer->EndPaint();
}
예제 #4
0
	void IncludeRef(int line_nr, const char *refstr)
	{
		TBNode *refnode = nullptr;
		if (*refstr == '@')
		{
			TBNode tmp;
			tmp.GetValue().SetString(refstr, TBValue::SET_AS_STATIC);
			refnode = TBNodeRefTree::FollowNodeRef(&tmp);
		}
		else // Local look-up
		{
			// Note: If we read to a target node that already contains
			//       nodes, we might look up nodes that's already there
			//       instead of new nodes.
			refnode = m_root_node->GetNode(refstr, TBNode::GET_MISS_POLICY_NULL);

			// Detect cycles
			TBNode *cycle_detection = m_target_node;
			while (cycle_detection && refnode)
			{
				if (cycle_detection == refnode)
					refnode = nullptr; // We have a cycle, so just fail the inclusion.
				cycle_detection = cycle_detection->GetParent();
			}
		}
		if (refnode)
			m_target_node->CloneChildren(refnode);
		else
		{
			TBStr err;
			err.SetFormatted("Include \"%s\" was not found!", refstr);
			OnError(line_nr, err);
		}
	}
예제 #5
0
void ResourceEditWindow::Load(const char *resource_file)
{
	m_resource_filename.Set(resource_file);
	SetText(resource_file);

	// Set the text of the source view
	m_source_edit->SetText("");

	if (TBFile *file = TBFile::Open(m_resource_filename, TBFile::MODE_READ))
	{
		TBTempBuffer buffer;
		if (buffer.Reserve(file->Size()))
		{
			uint32 size_read = file->Read(buffer.GetData(), 1, buffer.GetCapacity());
			m_source_edit->SetText(buffer.GetData(), size_read);
		}
		delete file;
	}
	else // Error, show message
	{
		TBStr text;
		text.SetFormatted("Could not load file %s", resource_file);
		if (TBMessageWindow *msg_win = new TBMessageWindow(GetParentRoot(), TBIDC("")))
			msg_win->Show("Error loading resource", text);
	}

	RefreshFromSource();
}
예제 #6
0
	virtual void OnError(int line_nr, const char *error)
	{
#ifdef TB_RUNTIME_DEBUG_INFO
		TBStr err;
		err.SetFormatted("%s(%d):Parse error: %s\n", m_filename, line_nr, error);
		TBDebugOut(err);
#endif // TB_RUNTIME_DEBUG_INFO
	}
예제 #7
0
void TBSelectList::ValidateList()
{
    if (!m_list_is_invalid)
        return;
    m_list_is_invalid = false;
    // FIX: Could delete and create only the changed items (faster filter change)

    // Remove old items
    while (TBWidget *child = m_layout.GetContentRoot()->GetFirstChild())
    {
        child->GetParent()->RemoveChild(child);
        delete child;
    }
    if (!m_source || !m_source->GetNumItems())
        return;

    // Create a sorted list of the items we should include using the current filter.
    TBTempBuffer sort_buf;
    if (!sort_buf.Reserve(m_source->GetNumItems() * sizeof(int)))
        return; // Out of memory
    int *sorted_index = (int *) sort_buf.GetData();

    // Populate the sorted index list
    int num_sorted_items = 0;
    for (int i = 0; i < m_source->GetNumItems(); i++)
        if (m_filter.IsEmpty() || m_source->Filter(i, m_filter))
            sorted_index[num_sorted_items++] = i;

    // Sort
    if (m_source->GetSort() != TB_SORT_NONE)
        insertion_sort<TBSelectItemSource*, int>(sorted_index, num_sorted_items, m_source, select_list_sort_cb);

    // Show header if we only show a subset of all items.
    if (!m_filter.IsEmpty())
    {
        if (TBWidget *widget = new TBTextField())
        {
            TBStr str;
            str.SetFormatted(g_tb_lng->GetString(m_header_lng_string_id), num_sorted_items, m_source->GetNumItems());
            widget->SetText(str);
            widget->SetSkinBg(TBIDC("TBList.header"));
            widget->SetState(WIDGET_STATE_DISABLED, true);
            widget->SetGravity(WIDGET_GRAVITY_ALL);
            widget->data.SetInt(-1);
            m_layout.GetContentRoot()->AddChild(widget);
        }
    }

    // Create new items
    for (int i = 0; i < num_sorted_items; i++)
        CreateAndAddItemAfter(sorted_index[i], nullptr);

    SelectItem(m_value, true);

    // FIX: Should not scroll just because we update the list. Only automatically first time!
    m_scroll_to_current = true;
}
예제 #8
0
void DemoApplication::RenderFrame(int window_w, int window_h)
{
	// Override RenderFrame without calling super, since we want
	// to inject code between BeginPaint/EndPaint.
	// Application::RenderFrame(window_w, window_h);

	// Render
	g_renderer->BeginPaint(window_w, window_h);
	GetRoot()->InvokePaint(TBWidget::PaintProps());

#if defined(TB_RUNTIME_DEBUG_INFO) && defined(TB_IMAGE)
	// Enable to debug image manager fragments
	//g_image_manager->Debug();
#endif

	frame_counter++;
	frame_counter_total++;

	// Update the FPS counter
	double time = TBSystem::GetTimeMS();
	if (time > frame_counter_reset_time + 1000)
	{
		fps = (int) ((frame_counter / (time - frame_counter_reset_time)) * 1000);
		frame_counter_reset_time = time;
		frame_counter = 0;
	}

	// Draw FPS
	TBWidgetValue *continuous_repaint_val = g_value_group.GetValue(TBIDC("continous-repaint"));
	bool continuous_repaint = continuous_repaint_val ? !!continuous_repaint_val->GetInt() : 0;

	TBStr str;
	if (continuous_repaint)
		str.SetFormatted("FPS: %d Frame %d", fps, frame_counter_total);
	else
		str.SetFormatted("Frame %d", frame_counter_total);
	GetRoot()->GetFont()->DrawString(5, 5, TBColor(255, 255, 255), str);

	g_renderer->EndPaint();

	// If we want continous updates or got animations running, reinvalidate immediately
	if (continuous_repaint || TBAnimationManager::HasAnimationsRunning())
		GetRoot()->Invalidate();
}
예제 #9
0
bool DemoApplication::Init()
{
	if (!Application::Init())
		return false;

	// Block new animations during Init.
	TBAnimationBlocker anim_blocker;

	// Run unit tests
	int num_failed_tests = TBRunTests();

	// TBSelectList and TBSelectDropdown widgets have a default item source that are fed with any items
	// specified in the resource files. But it is also possible to set any source which can save memory
	// and improve performance. Then you don't have to populate each instance with its own set of items,
	// for widgets that occur many times in a UI, always with the same items.
	// Here we prepare the name source, that is used in a few places.
	for (int i = 0; boy_names[i]; i++)
		advanced_source.AddItem(new AdvancedItem(boy_names[i++], TBIDC("boy_item"), true));
	for (int i = 0; girl_names[i]; i++)
		advanced_source.AddItem(new AdvancedItem(girl_names[i++], TBIDC("girl_item"), false));
	for (int i = 0; girl_names[i]; i++)
		name_source.AddItem(new TBGenericStringItem(girl_names[i++], TBIDC("girl_item")));
	for (int i = 0; boy_names[i]; i++)
		name_source.AddItem(new TBGenericStringItem(boy_names[i++], TBIDC("boy_item")));
	advanced_source.SetSort(TB_SORT_ASCENDING);
	name_source.SetSort(TB_SORT_ASCENDING);

	// Prepare a source with submenus (with eternal recursion) so we can test sub menu support.
	popup_menu_source.AddItem(new TBGenericStringItem("Option 1", TBIDC("opt 1")));
	popup_menu_source.AddItem(new TBGenericStringItem("Option 2", TBIDC("opt 2")));
	popup_menu_source.AddItem(new TBGenericStringItem("-"));
	popup_menu_source.AddItem(new TBGenericStringItem("Same submenu", &popup_menu_source));
	popup_menu_source.AddItem(new TBGenericStringItem("Long submenu", &name_source));
	// Give the first item a skin image
	popup_menu_source.GetItem(0)->SetSkinImage(TBIDC("Icon16"));

	new MainWindow();

	new EditWindow;

	new ListWindow(&name_source);

	new AdvancedListWindow(&advanced_source);

	new TabContainerWindow();

	if (num_failed_tests)
	{
		TBStr text;
		text.SetFormatted("There is %d failed tests!\nCheck the output for details.", num_failed_tests);
		TBMessageWindow *msg_win = new TBMessageWindow(GetRoot(), TBIDC(""));
		msg_win->Show("Testing results", text);
	}
	return true;
}
예제 #10
0
    TBStr GetIDString(const TBID &id)
    {
        TBStr str;
#ifdef TB_RUNTIME_DEBUG_INFO
        str.Append("\"");
        str.Append(id.debug_string);
        str.Append("\"");
#else
        str.SetFormatted("%u", (uint32)id);
#endif
        return str;
    }
예제 #11
0
const char *TBLanguage::GetString(const TBID &id)
{
	if (TBStr *str = strings.Get(id))
		return *str;
#ifdef TB_RUNTIME_DEBUG_INFO
	static TBStr tmp;
	tmp.SetFormatted("<TRANSLATE:%s>", id.debug_string.CStr());
	return tmp;
#else
	return "<TRANSLATE!>";
#endif
}
예제 #12
0
void TBHashTable::Debug()
{
    TBTempBuffer line;
    line.AppendString("Hash table: ");
    int total_count = 0;
    for (uint32 i = 0; i < m_num_buckets; i++)
    {
        int count = 0;
        ITEM *item = m_buckets[i];
        while (item)
        {
            count++;
            item = item->next;
        }
        TBStr tmp; tmp.SetFormatted("%d ", count);
        line.AppendString(tmp);
        total_count += count;
    }
    TBStr tmp; tmp.SetFormatted(" (total: %d of %d buckets)\n", total_count, m_num_buckets);
    line.AppendString(tmp);
    TBDebugOut(line.GetData());
}
예제 #13
0
파일: App.cpp 프로젝트: BibleUs/turbobadger
	void ShowScreenInfo()
	{
		TBStr text;
		text.SetFormatted(	"Screen DPI: %d\n"
							"Closest skin DPI: %d\n"
							"Root dimensions: %dx%dpx\n"
							"100dp equals %dpx (Based on closest skin DPI and screen DPI)",
							TBSystem::GetDPI(),
							g_tb_skin->GetDimensionConverter()->GetDstDPI(),
							GetParentRoot()->GetRect().w, GetParentRoot()->GetRect().h,
							g_tb_skin->GetDimensionConverter()->DpToPx(100));
		TBMessageWindow *msg_win = new TBMessageWindow(GetParentRoot(), TBIDC(""));
		msg_win->Show("Screen info", text);
	}
예제 #14
0
void ScrollContainerWindow::OnMessageReceived(TBMessage *msg)
{
	if (msg->message == TBIDC("new button") && msg->data)
	{
		if (TBWidget *target = GetWidgetByID(msg->data->id1))
		{
			TBStr str;
			str.SetFormatted("Remove %d", msg->data->v1.GetInt());
			TBButton *button = new TBButton;
			button->SetID(TBIDC("remove button"));
			button->SetText(str);
			target->AddChild(button);
		}
	}
}
예제 #15
0
void ResourceEditWindow::AddWidgetListItemsRecursive(TBWidget *widget, int depth)
{
	if (depth > 0) // Ignore the root
	{
		// Add a new ResourceItem for this widget
		TBStr str;
		const char *classname = widget->GetClassName();
		if (!*classname)
			classname = "<Unknown widget type>";
		str.SetFormatted("% *s%s", depth - 1, "", classname);

		if (ResourceItem *item = new ResourceItem(widget, str))
			m_widget_list_source.AddItem(item);
	}

	for (TBWidget *child = widget->GetFirstChild(); child; child = child->GetNext())
		AddWidgetListItemsRecursive(child, depth + 1);
}
예제 #16
0
	virtual void OnProcessStates()
	{
		// Update the disabled state of undo/redo buttons, and caret info.

		if (TBEditField *edit = GetWidgetByIDAndType<TBEditField>(TBIDC("editfield")))
		{
			if (TBWidget *undo = GetWidgetByID("undo"))
				undo->SetState(WIDGET_STATE_DISABLED, !edit->GetStyleEdit()->CanUndo());
			if (TBWidget *redo = GetWidgetByID("redo"))
				redo->SetState(WIDGET_STATE_DISABLED, !edit->GetStyleEdit()->CanRedo());
			if (TBTextField *info = GetWidgetByIDAndType<TBTextField>(TBIDC("info")))
			{
				TBStr text;
				text.SetFormatted("Caret ofs: %d", edit->GetStyleEdit()->caret.GetGlobalOfs());
				info->SetText(text);
			}
		}
	}
예제 #17
0
파일: App.cpp 프로젝트: BibleUs/turbobadger
	void TestSpeed(TEST test)
	{
		const char *title = "";
		const int iteration_count = 300;
		double total_time;

		if (test == TEST_INFLATE)
		{
			title = "Inflate + layout speed";
			double start_time = TBSystem::GetTimeMS();
			for(int i = 0; i < iteration_count; i++)
			{
				TBWindow *win = new TBWindow;
				g_widgets_reader->LoadFile(win, "layout/main_layout.tb.txt");
				win->SetText(title);
				win->SetSize(100 + i, 100 + i);
				win->Close();
			}
			total_time = TBSystem::GetTimeMS() - start_time;
		}
		else
		{
			title = "Resizing layout speed";
			TBWindow *win = new TBWindow;
			win->SetText(title);
			g_widgets_reader->LoadFile(win, "layout/main_layout.tb.txt");

			double start_time = TBSystem::GetTimeMS();
			for(int i = 0; i < iteration_count; i++)
				win->SetSize(100 + i, 100 + i);
			total_time = TBSystem::GetTimeMS() - start_time;

			win->Close();
		}

		TBStr text;
		text.SetFormatted(	"Total time for %d iterations:\n"
							"%dms\n"
							"Average time per iteration:\n"
							"%.2fms",
							iteration_count, (int)(total_time), (float)(total_time) / (float)iteration_count);
		TBMessageWindow *msg_win = new TBMessageWindow(GetParentRoot(), TBIDC(""));
		msg_win->Show(title, text);
	}
예제 #18
0
void MainWindow::OnMessageReceived(TBMessage *msg)
{
	if (msg->message == TBIDC("instantmsg"))
	{
		TBMessageWindow *msg_win = new TBMessageWindow(this, TBIDC("test_dialog"));
		msg_win->Show("Message window", "Instant message received!");
	}
	else if (msg->message == TBIDC("busy"))
	{
		// Keep the message queue busy by posting another "busy" message.
		PostMessage(TBIDC("busy"), nullptr);
	}
	else if (msg->message == TBIDC("delayedmsg"))
	{
		TBStr text;
		text.SetFormatted("Delayed message received!\n\n"
							"It was received %d ms after its intended fire time.",
							(int)(TBSystem::GetTimeMS() - msg->GetFireTime()));
		TBMessageWindow *msg_win = new TBMessageWindow(this, TBIDC(""));
		msg_win->Show("Message window", text);
	}
}
예제 #19
0
	void IncludeFile(int line_nr, const char *filename)
	{
		// Read the included file into a new TBNode and then
		// move all the children to m_target_node.
		TBTempBuffer include_filename;
		include_filename.AppendPath(m_filename);
		include_filename.AppendString(filename);
		TBNode content;
		if (content.ReadFile(include_filename.GetData()))
		{
			while (TBNode *content_n = content.GetFirstChild())
			{
				content.Remove(content_n);
				m_target_node->Add(content_n);
			}
		}
		else
		{
			TBStr err;
			err.SetFormatted("Referenced file \"%s\" was not found!", include_filename.GetData());
			OnError(line_nr, err);
		}
	}
예제 #20
0
bool MainWindow::OnEvent(const TBWidgetEvent &ev)
{
	if (ev.type == EVENT_TYPE_CLICK)
	{
		if (ev.target->GetID() == TBIDC("new"))
		{
			new MainWindow();
			return true;
		}
		if (ev.target->GetID() == TBIDC("msg"))
		{
			PostMessage(TBIDC("instantmsg"), nullptr);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("busymsg"))
		{
			if (ev.target->GetValue() == 1)
			{
				// Post the first "busy" message when we check the checkbox.
				assert(!GetMessageByID(TBIDC("busy")));
				if (!GetMessageByID(TBIDC("busy")))
				{
					PostMessage(TBIDC("busy"), nullptr);
					TBMessageWindow *msg_win = new TBMessageWindow(this, TBIDC("test_dialog"));
					msg_win->Show("Message window", "The message loop is now constantly busy with messages to process.\n\n"
								"The main thread should be working hard, but input & animations should still be running smoothly.");
				}
			}
			else
			{
				// Remove any pending "busy" message when we uncheck the checkbox.
				assert(GetMessageByID(TBIDC("busy")));
				if (TBMessage *busymsg = GetMessageByID(TBIDC("busy")))
					DeleteMessage(busymsg);
			}
			return true;
		}
		else if (ev.target->GetID() == TBIDC("delayedmsg"))
		{
			PostMessageDelayed(TBIDC("delayedmsg"), nullptr, 2000);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("TBWindow.close"))
		{
			// Intercept the TBWindow.close message and stop it from bubbling
			// to TBWindow (prevent the window from closing)
			TBMessageWindow *msg_win = new TBMessageWindow(this, TBIDC("confirm_close_dialog"));
			TBMessageWindowSettings settings(TB_MSG_YES_NO, TBIDC("Icon48"));
			settings.dimmer = true;
			settings.styling = true;
			msg_win->Show("Are you sure?", "Really <color #0794f8>close</color> the window?", &settings);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("confirm_close_dialog"))
		{
			if (ev.ref_id == TBIDC("TBMessageWindow.yes"))
				Close();
			return true;
		}
		else if (ev.target->GetID() == TBIDC("reload skin bitmaps"))
		{
			int reload_count = 10;
			double t1 = TBSystem::GetTimeMS();
			for (int i = 0; i < reload_count; i++)
				g_tb_skin->ReloadBitmaps();
			double t2 = TBSystem::GetTimeMS();

			TBStr message;
			message.SetFormatted("Reloading the skin graphics %d times took %dms", reload_count, (int)(t2 - t1));
			TBMessageWindow *msg_win = new TBMessageWindow(ev.target, TBID());
			msg_win->Show("GFX load performance", message);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test context lost"))
		{
			g_renderer->InvokeContextLost();
			g_renderer->InvokeContextRestored();
			TBMessageWindow *msg_win = new TBMessageWindow(ev.target, TBID());
			msg_win->Show("Context lost & restore",
							"Called InvokeContextLost and InvokeContextRestored.\n\n"
							"Does everything look fine?");
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-layout"))
		{
			TBStr resource_file("Demo/demo01/ui_resources/");
			resource_file.Append(ev.target->data.GetString());
			new LayoutWindow(resource_file);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-connections"))
		{
			new ConnectionWindow();
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-list"))
		{
			new AdvancedListWindow(&advanced_source);
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-image"))
		{
			new ImageWindow();
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-page"))
		{
			new PageWindow();
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-animations"))
		{
			new AnimationsWindow();
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-scroll-container"))
		{
			new ScrollContainerWindow();
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-skin-conditions"))
		{
			(new DemoWindow())->LoadResourceFile("Demo/demo01/ui_resources/test_skin_conditions01.tb.txt");
			(new DemoWindow())->LoadResourceFile("Demo/demo01/ui_resources/test_skin_conditions02.tb.txt");
			return true;
		}
		else if (ev.target->GetID() == TBIDC("test-resource-edit"))
		{
			ResourceEditWindow *res_edit_win = new ResourceEditWindow();
			res_edit_win->Load("Demo/demo01/ui_resources/resource_edit_test.tb.txt");
			GetParent()->AddChild(res_edit_win);
			return true;
		}
		else if (ev.type == EVENT_TYPE_CLICK && ev.target->GetID() == TBIDC("debug settings"))
		{
#ifdef TB_RUNTIME_DEBUG_INFO
			ShowDebugInfoSettingsWindow(GetParentRoot());
#else
			TBMessageWindow *msg_win = new TBMessageWindow(ev.target, TBID());
			msg_win->Show("Debug settings",
							"Debug settings is only available in builds "
							"compiled with TB_RUNTIME_DEBUG_INFO defined.\n\n"
							"Debug builds enable this by default.");
#endif
			return true;
		}
	}
	return DemoWindow::OnEvent(ev);
}