Skip to content

Instantly share code, notes, and snippets.

@PredatorMF
Last active October 22, 2018 13:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PredatorMF/18c8f50d72296f427eb6b2bdfa729dad to your computer and use it in GitHub Desktop.
Save PredatorMF/18c8f50d72296f427eb6b2bdfa729dad to your computer and use it in GitHub Desktop.
Urho3D TurboBadger integration
#include <Urho3D/UI/Window.h>
#include <Urho3D/Core/Context.h>
#include <Urho3D/Core/Object.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/UI/UIElement.h>
#include <Urho3D/UI/UIEvents.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/GraphicsEvents.h>
#include <Urho3D/Graphics/VertexBuffer.h>
#include <Urho3D/Graphics/Texture2D.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/IO/FileSystem.h>
#include <Urho3D/Input/InputEvents.h>
#include <tb_font_renderer.h>
#include <tb_widgets.h>
#include <tb_bitmap_fragment.h>
#include <tb_system.h>
#include <tb_msg.h>
#include <tb_language.h>
#include <animation/tb_animation.h>
#include <animation/tb_widget_animation.h>
#include "STB/stb_image.h"
#include <SDL/SDL.h>
#include "gui/tb_ui_renderer.h"
#define QAL_VAL 0x60000000 // value to offset qualifier keys from all other keys in the same hash map
#ifdef TB_FONT_RENDERER_TBBF
void register_tbbf_font_renderer();
#endif
#ifdef TB_FONT_RENDERER_STB
void register_stb_font_renderer();
#endif
#ifdef TB_FONT_RENDERER_FREETYPE
void register_freetype_font_renderer();
#endif
namespace Urho3D {
namespace {
static Context* g_context = 0;
} // namespace
UTBBitmap::UTBBitmap(TBUI* renderer)
: renderer_(renderer), width_(0), height_(0) {
}
UTBBitmap::~UTBBitmap() {
renderer_->FlushBitmap(this);
texture_.Reset();
}
bool UTBBitmap::Init(int width, int height, tb::uint32 *data) {
texture_ = SharedPtr<Texture2D>(new Texture2D(renderer_->GetContext()));
width_ = width;
height_ = height;
// set texture format
texture_->SetMipsToSkip(QUALITY_LOW, 0);
texture_->SetNumLevels(1);
texture_->SetSize(width_, height_, Graphics::GetRGBAFormat());
// set uv modes
texture_->SetAddressMode(COORD_U, ADDRESS_WRAP);
texture_->SetAddressMode(COORD_V, ADDRESS_WRAP),
texture_->SetBorderColor(Color(0.0f, 0.0f, 0.0f, 0.0f));
SetData(data);
return true;
}
void UTBBitmap::SetData(tb::uint32 *_pdata) {
renderer_->FlushBitmap(this);
texture_->SetData(0, 0, 0, width_, height_, _pdata);
}
UTBMultiTexture::UTBMultiTexture(Context* context)
: Texture2D(context), vs_(0), ps_(0) {
}
class TBUIRootWidget : public tb::TBWidget {
public:
// For safe typecasting
TBOBJECT_SUBCLASS(TBUIRootWidget, tb::TBWidget)
TBUIRootWidget(TBUI* renderer) : renderer_(renderer) {}
virtual void OnInvalid() {
renderer_->OnRootRepaint();
};
TBUI* GetRenderer() { return renderer_; }
private:
TBUI* renderer_;
};
// static
TBUI* TBUI::_instance = 0;
// static
TBUI* TBUI::Instance() {
return _instance;
}
TBUI::TBUI(Context* context)
: Object(context)
, TBRendererBatcher()
, needs_repaint_(false)
, mouse_buttons_(0) {
_instance = this;
g_context = context;
// Do 10 repaints at the beginning
repaint_count_hack_ = 10;
// init tb core
tb_core_init(this);
root_ = new TBUIRootWidget(this);
root_->Invalidate();
root_->InvalidateStates();
vertexBuffer_ = new VertexBuffer(context_);
Graphics* graphics = GetSubsystem<Graphics>();
OnResizeWin(graphics->GetWidth(), graphics->GetHeight());
}
TBUI::~TBUI() {
_instance = 0;
vertex_data_.Clear();
batches_.Clear();
uKeytoTBkeyMap.Clear();
tb::TBWidgetsAnimationManager::Shutdown();
// shutdown
tb::tb_core_shutdown();
delete root_;
}
tb::TBWidget& TBUI::Root() {
return *root_;
}
void TBUI::OnResizeWin(int width, int height) {
m_screen_rect = tb::TBRect(0, 0, width, height);
root_->SetRect(m_screen_rect);
}
void TBUI::Init() {
ResourceCache* cache = GetSubsystem<ResourceCache>();
// load resources
LoadDefaultResources();
// map keys
CreateKeyMap();
// register handlers
RegisterHandlers();
}
void TBUI::Shutdown() {
}
void TBUI::LoadDefaultResources() {
using namespace tb;
g_tb_lng->Load("TBUI/resources/language/lng_en.tb.txt");
// Load the default skin, and override skin that contains the graphics specific to the demo.
g_tb_skin->Load("TBUI/resources/default_skin/skin.tb.txt");
// **README**
// - define TB_FONT_RENDERER_FREETYPE in tb_config.h for non-demo
#ifdef TB_FONT_RENDERER_TBBF
register_tbbf_font_renderer();
#endif
#ifdef TB_FONT_RENDERER_STB
register_stb_font_renderer();
#endif
#ifdef TB_FONT_RENDERER_FREETYPE
register_freetype_font_renderer();
#endif
// Add fonts we can use to the font manager.
#if defined(TB_FONT_RENDERER_STB) || defined(TB_FONT_RENDERER_FREETYPE)
g_font_manager->AddFontInfo("Fonts/Roboto-Regular.ttf", "Roboto");
g_font_manager->AddFontInfo("Fonts/Roboto-Bold.ttf", "Roboto-Bold");
g_font_manager->AddFontInfo("Fonts/fontawesome-webfont.ttf", "fa");
#endif
#ifdef TB_FONT_RENDERER_TBBF
g_font_manager->AddFontInfo("TBUI/resources/default_font/segoe_white_with_shadow.tb.txt", "Segoe");
g_font_manager->AddFontInfo("TBUI/fonts/neon.tb.txt", "Neon");
g_font_manager->AddFontInfo("TBUI/fonts/orangutang.tb.txt", "Orangutang");
g_font_manager->AddFontInfo("TBUI/fonts/orange.tb.txt", "Orange");
#endif
// Set the default font description for widgets to one of the fonts we just added
TBFontDescription fd;
#if !defined(TB_FONT_RENDERER_FREETYPE)
fd.SetID(TBIDC("Segoe"));
#else
fd.SetID(TBIDC("Roboto"));
#endif
fd.SetSize(g_tb_skin->GetDimensionConverter()->DpToPx(14));
g_font_manager->SetDefaultFontDescription(fd);
// Create the font now.
TBFontFace *font = g_font_manager->CreateFontFace(g_font_manager->GetDefaultFontDescription());
// Render some glyphs in one go now since we know we are going to use them. It would work fine
// without this since glyphs are rendered when needed, but with some extra updating of the glyph bitmap.
if (font) {
font->RenderGlyphs(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~•·åäöÅÄÖ");
}
root_->SetSkinBg(TBIDC("background"));
TBWidgetsAnimationManager::Init();
}
void TBUI::CreateKeyMap() {
using namespace tb;
// special keys
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_UP, TB_KEY_UP));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_DOWN, TB_KEY_DOWN));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_LEFT, TB_KEY_LEFT));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_RIGHT, TB_KEY_RIGHT));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_PAGEUP, TB_KEY_PAGE_UP));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_PAGEDOWN, TB_KEY_PAGE_DOWN));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_HOME, TB_KEY_HOME));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_END, TB_KEY_END));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_TAB, TB_KEY_TAB));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_BACKSPACE, TB_KEY_BACKSPACE));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_INSERT, TB_KEY_INSERT));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_DELETE, TB_KEY_DELETE));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_RETURN, TB_KEY_ENTER));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_ESCAPE, TB_KEY_ESC));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F1, TB_KEY_F1));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F2, TB_KEY_F2));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F3, TB_KEY_F3));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F4, TB_KEY_F4));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F5, TB_KEY_F5));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F6, TB_KEY_F6));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F7, TB_KEY_F7));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F8, TB_KEY_F8));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F9, TB_KEY_F9));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F10, TB_KEY_F10));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F11, TB_KEY_F11));
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F12, TB_KEY_F12));
// qualifiers: add QAL_VAL to qual keys to separate their range from rest of the keys
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_SHIFT + QAL_VAL, TB_SHIFT));
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_CTRL + QAL_VAL, TB_CTRL));
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_ALT + QAL_VAL, TB_ALT));
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_ANY + QAL_VAL, TB_SUPER));
}
tb::TBBitmap* TBUI::CreateBitmap(int width, int height, tb::uint32 *data) {
using namespace tb;
UTBBitmap *bitmap = new UTBBitmap(this);
if (!bitmap->Init(width, height, data))
{
delete bitmap;
return nullptr;
}
return bitmap;
}
void TBUI::RenderBatch(Batch* batch) {
using namespace tb;
if (!batch->vertex_count)
return;
Texture2D* texture = NULL;
if (batch->bitmap) {
auto* tbuibitmap = (UTBBitmap*)batch->bitmap;
if (tbuibitmap->texture_)
texture = tbuibitmap->texture_;
}
UIBatch b(0, BLEND_ALPHA, scissor_, texture, &vertex_data_);
unsigned begin = b.vertexData_->Size();
b.vertexData_->Resize(begin + batch->vertex_count * UI_VERTEX_SIZE);
float* dest = &(b.vertexData_->At(begin));
b.vertexEnd_ = b.vertexData_->Size();
for (int i = 0; i < batch->vertex_count; i++) {
Vertex* v = &batch->vertex[i];
dest[0] = v->x;
dest[1] = v->y;
dest[2] = 0.0f;
((unsigned&)dest[3]) = v->col;
dest[4] = v->u;
dest[5] = v->v;
dest += UI_VERTEX_SIZE;
}
UIBatch::AddOrMerge(b, batches_);
}
void TBUI::SetClipRect(const tb::TBRect &rect) {
scissor_.top_ = rect.y;
scissor_.bottom_ = rect.y + rect.h;
scissor_.left_ = rect.x;
scissor_.right_ = rect.x + rect.w;
}
void TBUI::BeginPaint(int render_target_w, int render_target_h) {
vertex_data_.Clear();
batches_.Clear();
TBRendererBatcher::BeginPaint(render_target_w, render_target_h);
}
void TBUI::EndPaint() {
TBRendererBatcher::EndPaint();
// Update quad geometry into the vertex buffer
// Resize the vertex buffer first if too small or much too large
unsigned numVertices = vertex_data_.Size() / UI_VERTEX_SIZE;
if (vertexBuffer_->GetVertexCount() < numVertices || vertexBuffer_->GetVertexCount() > numVertices * 2)
vertexBuffer_->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true);
if (!vertex_data_.Empty())
vertexBuffer_->SetData(&vertex_data_[0]);
else
vertexBuffer_->SetSize(0, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true);
}
void TBUI::Render() {
if (batches_.Empty()) {
return;
}
Graphics* graphics = GetSubsystem<Graphics>();
IntVector2 size;
size.x_ = graphics->GetWidth();
size.y_ = graphics->GetHeight();
bool scissorEnabled = true;
IntRect rect(0, 0, size.x_, size.y_);
Vector2 invScreenSize(1.0f / (float)size.x_, 1.0f / (float)size.y_);
Vector2 scale(2.0f * invScreenSize.x_, -2.0f * invScreenSize.y_);
Vector2 offset(-1.0f, 1.0f);
Matrix4 projection(Matrix4::IDENTITY);
projection.m00_ = scale.x_;
projection.m03_ = offset.x_;
projection.m11_ = scale.y_;
projection.m13_ = offset.y_;
projection.m22_ = 1.0f;
projection.m23_ = 0.0f;
projection.m33_ = 1.0f;
graphics->ClearParameterSources();
graphics->SetColorWrite(true);
graphics->SetCullMode(CULL_NONE);
graphics->SetDepthTest(CMP_ALWAYS);
graphics->SetDepthWrite(false);
graphics->SetFillMode(FILL_SOLID);
graphics->SetStencilTest(false);
graphics->SetViewport(rect);
graphics->SetVertexBuffer(vertexBuffer_);
ShaderVariation* noTextureVS = graphics->GetShader(VS, "Imgui", "VERTEXCOLOR");
ShaderVariation* diffTextureVS = graphics->GetShader(VS, "Imgui", "DIFFMAP VERTEXCOLOR");
ShaderVariation* noTexturePS = graphics->GetShader(PS, "Imgui", "VERTEXCOLOR");
ShaderVariation* diffTexturePS = graphics->GetShader(PS, "Imgui", "DIFFMAP VERTEXCOLOR");
ShaderVariation* diffMaskTexturePS = graphics->GetShader(PS, "Imgui", "DIFFMAP ALPHAMASK VERTEXCOLOR");
ShaderVariation* alphaTexturePS = graphics->GetShader(PS, "Imgui", "ALPHAMAP VERTEXCOLOR");
unsigned alphaFormat = Graphics::GetAlphaFormat();
for (auto batch: batches_) {
if (batch.vertexStart_ == batch.vertexEnd_)
continue;
ShaderVariation* ps;
ShaderVariation* vs;
bool is_multitexture = false;
if (batch.texture_)
is_multitexture = batch.texture_->IsInstanceOf<UTBMultiTexture>();
if (!batch.texture_) {
ps = noTexturePS;
vs = noTextureVS;
} else {
// if texture is Texture2D
if (!is_multitexture) {
// If texture contains only an alpha channel, use alpha shader (for fonts)
vs = diffTextureVS;
if (batch.texture_->GetFormat() == alphaFormat)
ps = alphaTexturePS;
else if (batch.blendMode_ != BLEND_ALPHA && batch.blendMode_ != BLEND_ADDALPHA && batch.blendMode_ != BLEND_PREMULALPHA)
ps = diffMaskTexturePS;
else
ps = diffTexturePS;
} else {
// when texture is UTBMultiTexture and has custom shaders
UTBMultiTexture* multitexture = batch.texture_->Cast<UTBMultiTexture>();
vs = multitexture->vs_ ? multitexture->vs_ : diffTextureVS;
ps = multitexture->ps_ ? multitexture->ps_ : diffTexturePS;
}
}
graphics->SetShaders(vs, ps);
if (graphics->NeedParameterUpdate(SP_OBJECT, this))
graphics->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY);
if (graphics->NeedParameterUpdate(SP_CAMERA, this))
graphics->SetShaderParameter(VSP_VIEWPROJ, projection);
bool need_material_update = graphics->NeedParameterUpdate(SP_MATERIAL, this);
if (need_material_update)
graphics->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
graphics->SetBlendMode(batch.blendMode_);
graphics->SetScissorTest(scissorEnabled, batch.scissor_);
if (!batch.texture_ || !batch.texture_->IsInstanceOf<UTBMultiTexture>()) {
graphics->SetTexture(0, batch.texture_);
} else if (is_multitexture) {
UTBMultiTexture* multitexture = batch.texture_->Cast<UTBMultiTexture>();
// apply shader parameters
for (auto param : multitexture->shader_parameters_) {
graphics->SetShaderParameter(param.first_, param.second_);
}
// apply textures
for (auto it = multitexture->additional_textures_.Begin(); it != multitexture->additional_textures_.End(); ++it) {
graphics->SetTexture(it->first_, it->second_);
}
}
graphics->Draw(TRIANGLE_LIST, batch.vertexStart_ / UI_VERTEX_SIZE, (batch.vertexEnd_ - batch.vertexStart_) /
UI_VERTEX_SIZE);
}
}
void TBUI::OnRootRepaint() {
if (!needs_repaint_) {
needs_repaint_ = true;
}
}
void TBUI::RegisterHandlers() {
// timer
SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(TBUI, HandleUpdate));
// screen resize and renderer
SubscribeToEvent(E_SCREENMODE, URHO3D_HANDLER(TBUI, HandleScreenMode));
// input
SubscribeToEvent(E_SDLRAWINPUT, URHO3D_HANDLER(TBUI, OnRawEvent));
}
void TBUI::HandleUpdate(StringHash eventType, VariantMap& eventData) {
using namespace tb;
// msg timer
double t = TBMessageHandler::GetNextMessageFireTime();
if (t != TB_NOT_SOON && t <= TBSystem::GetTimeMS()) {
TBMessageHandler::ProcessMessages();
}
}
void TBUI::HandleScreenMode(StringHash eventType, VariantMap& eventData) {
using namespace ScreenMode;
OnResizeWin(eventData[P_WIDTH].GetInt(), eventData[P_HEIGHT].GetInt());
}
void TBUI::HandleEndFrame(StringHash eventType, VariantMap& eventData) {
using namespace tb;
TBAnimationManager::Update();
TBWidgetValue *continuous_repaint_val = g_value_group.GetValue(TBIDC("continous-repaint"));
bool continuous_repaint = continuous_repaint_val ? !!continuous_repaint_val->GetInt() : 0;
if (continuous_repaint || (repaint_count_hack_ > 0) || needs_repaint_ || TBAnimationManager::HasAnimationsRunning()) {
if (repaint_count_hack_ > 0 && !needs_repaint_)
repaint_count_hack_--;
root_->InvokeProcessStates();
root_->InvokeProcess();
tb::TBRect root_rect(root_->GetRect());
scissor_ = Urho3D::IntRect(0, 0, root_rect.w, root_rect.h);
BeginPaint(root_rect.w, root_rect.h);
root_->InvokePaint(TBWidget::PaintProps());
// If animations are running, reinvalidate immediately
if (TBAnimationManager::HasAnimationsRunning()) {
root_->Invalidate();
}
EndPaint();
needs_repaint_ = false;
}
Render();
}
void TBUI::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace MouseButtonDown;
int mouseButtons = eventData[P_BUTTONS].GetInt();
int qualifiers = eventData[P_QUALIFIERS].GetInt();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
// exit if not the left mb
if (mouseButtons != MOUSEB_LEFT)
return;
root_->InvokePointerDown(last_mouse_pos_.x_, last_mouse_pos_.y_, 1, modKey, false);
}
void TBUI::HandleMouseButtonUp(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace MouseButtonUp;
int qualifiers = eventData[P_QUALIFIERS].GetInt();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false);
}
void TBUI::HandleMouseMove(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace MouseMove;
int qualifiers = eventData[P_QUALIFIERS].GetInt();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
last_mouse_pos_ = IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt());
root_->InvokePointerMove(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false);
}
void TBUI::HandleMouseWheel(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace MouseWheel;
int qualifiers = eventData[P_QUALIFIERS].GetInt();
int delta = eventData[P_WHEEL].GetInt();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
root_->InvokeWheel(last_mouse_pos_.x_, last_mouse_pos_.y_, 0, -delta, modKey);
}
void TBUI::HandleKeyDown(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace KeyDown;
int qualifiers = eventData[P_QUALIFIERS].GetInt();
int key = eventData[P_KEY].GetInt();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
SPECIAL_KEY spKey = (SPECIAL_KEY)FindTBKey(key);
// exit if not a special key
if (spKey == TB_KEY_UNDEFINED)
return;
root_->InvokeKey(key, spKey, modKey, true);
}
void TBUI::HandleKeyUp(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace KeyUp;
int qualifiers = eventData[P_QUALIFIERS].GetInt();
int key = eventData[P_KEY].GetInt();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
SPECIAL_KEY spKey = (SPECIAL_KEY)FindTBKey(key);
root_->InvokeKey(key, spKey, modKey, false);
}
void TBUI::HandleTextInput(StringHash eventType, VariantMap& eventData) {
using namespace tb;
using namespace TextInput;
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
int key = (int)eventData[P_TEXT].GetString().CString()[0];
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
root_->InvokeKey(key, TB_KEY_UNDEFINED, modKey, true);
}
static bool InvokeShortcut(SDL_Scancode code, tb::SPECIAL_KEY special_key, tb::MODIFIER_KEYS modifierkeys, bool down) {
using namespace tb;
bool shortcut_key = (modifierkeys & TB_CTRL) ? true : false;
if (!TBWidget::focused_widget || !down || !shortcut_key)
return false;
bool reverse_key = (modifierkeys & TB_SHIFT) ? true : false;
TBID id;
if (code == SDL_SCANCODE_X)
id = TBIDC("cut");
else if (code == SDL_SCANCODE_C || special_key == TB_KEY_INSERT)
id = TBIDC("copy");
else if (code == SDL_SCANCODE_V || (special_key == TB_KEY_INSERT && reverse_key))
id = TBIDC("paste");
else if (code == SDL_SCANCODE_A)
id = TBIDC("selectall");
else if (code == SDL_SCANCODE_Z || code == SDL_SCANCODE_Y)
{
bool undo = code == SDL_SCANCODE_Z;
if (reverse_key)
undo = !undo;
id = undo ? TBIDC("undo") : TBIDC("redo");
}
else if (code == SDL_SCANCODE_N)
id = TBIDC("new");
else if (code == SDL_SCANCODE_O)
id = TBIDC("open");
else if (code == SDL_SCANCODE_S)
id = TBIDC("save");
else if (code == SDL_SCANCODE_W)
id = TBIDC("close");
else if (special_key == TB_KEY_PAGE_UP)
id = TBIDC("prev_doc");
else if (special_key == TB_KEY_PAGE_DOWN)
id = TBIDC("next_doc");
else
return false;
TBWidgetEvent ev(EVENT_TYPE_SHORTCUT);
ev.modifierkeys = modifierkeys;
ev.ref_id = id;
return TBWidget::focused_widget->InvokeEvent(ev);
}
void TBUI::OnRawEvent(StringHash eventType, VariantMap& args) {
if (args[SDLRawInput::P_CONSUMED].GetBool())
return;
using namespace tb;
auto evt = static_cast<SDL_Event*>(args[SDLRawInput::P_SDLEVENT].Get<void*>());
bool handled = false;
switch (evt->type)
{
case SDL_KEYUP:
case SDL_KEYDOWN:
{
using namespace KeyUp;
int key = evt->key.keysym.sym;
int code = evt->key.keysym.scancode;
auto down = evt->type == SDL_KEYDOWN;
int qualifiers = 0;
if (evt->key.keysym.mod & KMOD_CTRL)
qualifiers |= QUAL_CTRL;
if (evt->key.keysym.mod & KMOD_ALT)
qualifiers |= QUAL_ALT;
if (evt->key.keysym.mod & KMOD_SHIFT)
qualifiers |= QUAL_SHIFT;
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
SPECIAL_KEY spKey = (SPECIAL_KEY)FindTBKey(key);
if (InvokeShortcut(evt->key.keysym.scancode, spKey, modKey, down))
break;
// exit if not a special key
if (spKey == TB_KEY_UNDEFINED && modKey == 0)
return;
root_->InvokeKey(0, spKey, modKey, down);
break;
}
case SDL_TEXTINPUT:
{
using namespace tb;
using namespace TextInput;
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
const String& text = evt->text.text;
for (unsigned i = 0; i < text.LengthUTF8(); i += 1) {
int c = text.AtUTF8(i);
handled |= root_->InvokeKey(c, TB_KEY_UNDEFINED, modKey, true);
handled |= root_->InvokeKey(c, TB_KEY_UNDEFINED, modKey, false);
}
break;
}
case SDL_MOUSEWHEEL:
{
using namespace tb;
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
int delta = evt->wheel.y;
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
handled |= root_->InvokeWheel(last_mouse_pos_.x_, last_mouse_pos_.y_, 0, -delta, modKey);
break;
}
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
{
using namespace tb;
using namespace MouseButtonUp;
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
bool down = evt->type == SDL_MOUSEBUTTONDOWN;
if (down) {
if (evt->button.button == SDL_BUTTON_LEFT)
mouse_buttons_ |= BUTTON_LEFT;
if (evt->button.button == SDL_BUTTON_RIGHT)
mouse_buttons_ |= BUTTON_RIGHT;
if (evt->button.button == SDL_BUTTON_MIDDLE)
mouse_buttons_ |= BUTTON_MIDDLE;
} else {
if (evt->button.button == SDL_BUTTON_LEFT)
mouse_buttons_ &= BUTTON_LEFT;
if (evt->button.button == SDL_BUTTON_RIGHT)
mouse_buttons_ &= BUTTON_RIGHT;
if (evt->button.button == SDL_BUTTON_MIDDLE)
mouse_buttons_ &= BUTTON_MIDDLE;
}
/*if (!down && evt->button.button == SDL_BUTTON_RIGHT) {
//root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false);
if (TBWidget::hovered_widget) {
TBWidget::hovered_widget->ConvertFromRoot(last_mouse_pos_.x_, last_mouse_pos_.y_);
TBWidgetEvent ev(EVENT_TYPE_CONTEXT_MENU, last_mouse_pos_.x_, last_mouse_pos_.y_, false, modKey);
handled |= TBWidget::hovered_widget->InvokeEvent(ev);
if (handled)
break;
}
}*/
if (down)
handled |= root_->InvokePointerDown(last_mouse_pos_.x_, last_mouse_pos_.y_, evt->button.clicks, modKey, false);
else
handled |= root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false);
}
case SDL_MOUSEMOTION:
{
using namespace tb;
using namespace MouseMove;
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
last_mouse_pos_ = IntVector2(evt->motion.x, evt->motion.y);
root_->InvokePointerMove(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false);
break;
}
case SDL_FINGERUP:
{
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
handled |= root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, true);
}
case SDL_FINGERDOWN:
{
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
handled |= root_->InvokePointerDown(last_mouse_pos_.x_, last_mouse_pos_.y_, 1, modKey, true);
}
case SDL_FINGERMOTION:
{
using namespace tb;
using namespace MouseMove;
int qualifiers = GetSubsystem<Input>()->GetQualifiers();
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL);
last_mouse_pos_ = IntVector2(args[P_X].GetInt(), args[P_Y].GetInt());
root_->InvokePointerMove(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, true);
break;
}
default:
break;
}
switch (evt->type)
{
case SDL_KEYUP:
case SDL_KEYDOWN:
case SDL_TEXTINPUT:
args[SDLRawInput::P_CONSUMED] = handled;
break;
case SDL_MOUSEWHEEL:
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEMOTION:
case SDL_FINGERUP:
case SDL_FINGERDOWN:
case SDL_FINGERMOTION:
args[SDLRawInput::P_CONSUMED] = handled;
break;
default:
break;
}
}
// TB special and quality keys func
int TBUI::FindTBKey(int key) {
HashMap<int, int>::Iterator itr = uKeytoTBkeyMap.Find(key);
int itbkey = 0;
if (itr != uKeytoTBkeyMap.End())
itbkey = itr->second_;
return itbkey;
}
class UTBFile : public tb::TBFile {
public:
UTBFile(Context *context)
: file_size_(0)
, context_(context) {
}
virtual ~UTBFile() {
if (file_) {
file_->Close();
file_.Reset();
}
}
bool OpenFile(const char* filename) {
ResourceCache* cache = context_->GetSubsystem<ResourceCache>();
file_ = cache->GetFile(filename);
if (file_) {
file_size_ = file_->Seek((unsigned)-1);
file_->Seek(0);
}
return !!file_;
}
virtual long Size() {
return (long)file_size_;
}
virtual size_t Read(void *buf, size_t elemSize, size_t count) {
if (!file_)
return 0;
return file_->Read(buf, elemSize * count);
}
protected:
Context* context_;
SharedPtr<File> file_;
unsigned file_size_;
};
} // namespace Urho3D
namespace tb {
// static
TBFile* TBFile::Open(const char *filename, tb::TBFile::TBFileMode) {
Urho3D::UTBFile* file = new Urho3D::UTBFile(Urho3D::g_context);
if (!file->OpenFile(filename)) {
delete file;
file = NULL;
}
return file;
}
// static
void TBSystem::RescheduleTimer(double fire_time) {
}
class STBI_Loader : public TBImageLoader {
public:
int width, height;
unsigned char *data;
STBI_Loader() : width(0), height(0), data(nullptr) {}
~STBI_Loader() { stbi_image_free(data); }
virtual int Width() { return width; }
virtual int Height() { return height; }
virtual uint32 *Data() { return (uint32*)data; }
};
TBImageLoader *TBImageLoader::CreateFromFile(const char *filename) {
TBTempBuffer buf;
if (buf.AppendFile(filename)) {
int w, h, comp;
if (unsigned char *img_data = stbi_load_from_memory((unsigned char*)buf.GetData(), buf.GetAppendPos(), &w, &h, &comp, 4)) {
if (STBI_Loader *img = new STBI_Loader()) {
img->width = w;
img->height = h;
img->data = img_data;
return img;
} else
stbi_image_free(img_data);
}
}
return nullptr;
}
/** Empty the contents of the clipboard. */
// static
void TBClipboard::Empty() {
SDL_SetClipboardText("");
}
/** Return true if the clipboard currently contains text. */
//static
bool TBClipboard::HasText() {
return SDL_HasClipboardText();
}
/** Set the text of the clipboard in UTF-8 format. */
// static
bool TBClipboard::SetText(const char *text) {
return SDL_SetClipboardText(text) == 0;
}
/** Get the text from the clipboard in UTF-8 format.
Returns true on success. */
// static
bool TBClipboard::GetText(TBStr &text) {
char* sdl_text = SDL_GetClipboardText();
text.Set(sdl_text);
SDL_free(sdl_text);
return true;
}
} // namespace tb
#ifndef __TBUI_RENDERER_H__
#define __TBUI_RENDERER_H__
#pragma once
#include "Urho3D/Graphics/Texture2D.h"
#include "Urho3D/UI/UIElement.h"
#include "Urho3D/Core/Object.h"
#include "tb_renderer.h"
#include "tb_widgets_reader.h"
#include "renderers/tb_renderer_batcher.h"
namespace Urho3D {
class Context;
class VertexBuffer;
class Texture2D;
class TBUIRootWidget;
class TBUI;
class ShaderVariation;
class UTBBitmap : public tb::TBBitmap, public tb::TBTypedObject {
public:
TBOBJECT_SUBCLASS(UTBBitmap, tb::TBTypedObject)
UTBBitmap(TBUI* renderer);
~UTBBitmap();
virtual bool Init(int width, int height, tb::uint32 *data);
virtual void SetData(tb::uint32 *_pdata);
virtual int Width() { return width_; }
virtual int Height() { return height_; }
TBUI* renderer_;
SharedPtr<Texture2D> texture_;
int width_;
int height_;
};
class UTBMultiTexture : public Texture2D {
URHO3D_OBJECT(UTBMultiTexture, Texture2D)
public:
UTBMultiTexture(Context* context);
HashMap<int, SharedPtr<Texture2D>> additional_textures_;
ShaderVariation* ps_;
ShaderVariation* vs_;
VariantMap shader_parameters_;
};
class TBUI : public Object, public tb::TBRendererBatcher {
URHO3D_OBJECT(TBUI, Object)
public:
typedef enum {
BUTTON_LEFT = 1 << 0,
BUTTON_RIGHT = 1 << 1,
BUTTON_MIDDLE = 1 << 2,
} MouseButtons;
TBUI(Context* context);
virtual ~TBUI();
static TBUI* Instance();
void Init();
void Shutdown();
void LoadDefaultResources();
tb::TBWidget& Root();
void SetClipRect(const tb::TBRect &rect);
// override functions
virtual void BeginPaint(int width, int height) override;
virtual void EndPaint() override;
virtual tb::TBBitmap* CreateBitmap(int width, int height, tb::uint32* data) override;
virtual void RenderBatch(Batch* batch);
void Render();
void HandleEndFrame(StringHash eventType, VariantMap& eventData);
/// Returns currently pressed mouse buttons
int GetPressedMouseButtons() const { return mouse_buttons_; }
private:
friend class TBUIRootWidget;
bool needs_repaint_;
int repaint_count_hack_;
IntRect scissor_;
TBUIRootWidget* root_;
PODVector<float> vertex_data_;
SharedPtr<VertexBuffer> vertexBuffer_;
PODVector<UIBatch> batches_;
HashMap<int, int> uKeytoTBkeyMap;
IntVector2 last_mouse_pos_;
int mouse_buttons_;
static TBUI* _instance;
void OnResizeWin(int width, int height);
void CreateKeyMap();
void RegisterHandlers();
void HandleUpdate(StringHash eventType, VariantMap& eventData);
// renderer
void HandleScreenMode(StringHash eventType, VariantMap& eventData);
// inputs
void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData);
void HandleMouseButtonUp(StringHash eventType, VariantMap& eventData);
void HandleMouseMove(StringHash eventType, VariantMap& eventData);
void HandleMouseWheel(StringHash eventType, VariantMap& eventData);
void HandleKeyDown(StringHash eventType, VariantMap& eventData);
void HandleKeyUp(StringHash eventType, VariantMap& eventData);
void HandleTextInput(StringHash eventType, VariantMap& eventData);
void OnRawEvent(StringHash eventType, VariantMap& args);
// TB special and quality keys func
int FindTBKey(int key);
void OnRootRepaint();
};
} // namespace Urho3D
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment