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. }
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); }
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(); }
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); } }
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(); }
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 }
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; }
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(); }
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; }
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; }
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 }
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()); }
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); }
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); } } }
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); }
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); } } }
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); }
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); } }
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); } }
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); }