|
|
@@ -17,550 +17,550 @@ namespace tb {
|
|
|
|
|
|
/*TB_TEXT_ALIGN StringToTextAlign(const char *align_str)
|
|
|
{
|
|
|
- TB_TEXT_ALIGN align = TB_TEXT_ALIGN_CENTER;
|
|
|
- if (strstr(state_str, "left")) align = TB_TEXT_ALIGN_LEFT;
|
|
|
- if (strstr(state_str, "center")) align = TB_TEXT_ALIGN_CENTER;
|
|
|
- if (strstr(state_str, "right")) align = TB_TEXT_ALIGN_RIGHT;
|
|
|
- return state;
|
|
|
+ TB_TEXT_ALIGN align = TB_TEXT_ALIGN_CENTER;
|
|
|
+ if (strstr(state_str, "left")) align = TB_TEXT_ALIGN_LEFT;
|
|
|
+ if (strstr(state_str, "center")) align = TB_TEXT_ALIGN_CENTER;
|
|
|
+ if (strstr(state_str, "right")) align = TB_TEXT_ALIGN_RIGHT;
|
|
|
+ return state;
|
|
|
}*/
|
|
|
|
|
|
SKIN_STATE StringToState(const char *state_str)
|
|
|
{
|
|
|
- SKIN_STATE state = SKIN_STATE_NONE;
|
|
|
- if (strstr(state_str, "all")) state |= SKIN_STATE_ALL;
|
|
|
- if (strstr(state_str, "disabled")) state |= SKIN_STATE_DISABLED;
|
|
|
- if (strstr(state_str, "focused")) state |= SKIN_STATE_FOCUSED;
|
|
|
- if (strstr(state_str, "pressed")) state |= SKIN_STATE_PRESSED;
|
|
|
- if (strstr(state_str, "selected")) state |= SKIN_STATE_SELECTED;
|
|
|
- if (strstr(state_str, "hovered")) state |= SKIN_STATE_HOVERED;
|
|
|
- return state;
|
|
|
+ SKIN_STATE state = SKIN_STATE_NONE;
|
|
|
+ if (strstr(state_str, "all")) state |= SKIN_STATE_ALL;
|
|
|
+ if (strstr(state_str, "disabled")) state |= SKIN_STATE_DISABLED;
|
|
|
+ if (strstr(state_str, "focused")) state |= SKIN_STATE_FOCUSED;
|
|
|
+ if (strstr(state_str, "pressed")) state |= SKIN_STATE_PRESSED;
|
|
|
+ if (strstr(state_str, "selected")) state |= SKIN_STATE_SELECTED;
|
|
|
+ if (strstr(state_str, "hovered")) state |= SKIN_STATE_HOVERED;
|
|
|
+ return state;
|
|
|
}
|
|
|
|
|
|
SKIN_ELEMENT_TYPE StringToType(const char *type_str)
|
|
|
{
|
|
|
- if (strcmp(type_str, "StretchBox") == 0)
|
|
|
- return SKIN_ELEMENT_TYPE_STRETCH_BOX;
|
|
|
- else if (strcmp(type_str, "Image") == 0)
|
|
|
- return SKIN_ELEMENT_TYPE_IMAGE;
|
|
|
- else if (strcmp(type_str, "Stretch Image") == 0)
|
|
|
- return SKIN_ELEMENT_TYPE_STRETCH_IMAGE;
|
|
|
- else if (strcmp(type_str, "Tile") == 0)
|
|
|
- return SKIN_ELEMENT_TYPE_TILE;
|
|
|
- else if (strcmp(type_str, "StretchBorder") == 0)
|
|
|
- return SKIN_ELEMENT_TYPE_STRETCH_BORDER;
|
|
|
- TBDebugOut("Skin error: Unknown skin type!\n");
|
|
|
- return SKIN_ELEMENT_TYPE_STRETCH_BOX;
|
|
|
+ if (strcmp(type_str, "StretchBox") == 0)
|
|
|
+ return SKIN_ELEMENT_TYPE_STRETCH_BOX;
|
|
|
+ else if (strcmp(type_str, "Image") == 0)
|
|
|
+ return SKIN_ELEMENT_TYPE_IMAGE;
|
|
|
+ else if (strcmp(type_str, "Stretch Image") == 0)
|
|
|
+ return SKIN_ELEMENT_TYPE_STRETCH_IMAGE;
|
|
|
+ else if (strcmp(type_str, "Tile") == 0)
|
|
|
+ return SKIN_ELEMENT_TYPE_TILE;
|
|
|
+ else if (strcmp(type_str, "StretchBorder") == 0)
|
|
|
+ return SKIN_ELEMENT_TYPE_STRETCH_BORDER;
|
|
|
+ TBDebugOut("Skin error: Unknown skin type!\n");
|
|
|
+ return SKIN_ELEMENT_TYPE_STRETCH_BOX;
|
|
|
}
|
|
|
|
|
|
TBSkinCondition::TARGET StringToTarget(const char *target_str)
|
|
|
{
|
|
|
- if (strcmp(target_str, "this") == 0)
|
|
|
- return TBSkinCondition::TARGET_THIS;
|
|
|
- else if (strcmp(target_str, "parent") == 0)
|
|
|
- return TBSkinCondition::TARGET_PARENT;
|
|
|
- else if (strcmp(target_str, "ancestors") == 0)
|
|
|
- return TBSkinCondition::TARGET_ANCESTORS;
|
|
|
- else if (strcmp(target_str, "prev sibling") == 0)
|
|
|
- return TBSkinCondition::TARGET_PREV_SIBLING;
|
|
|
- else if (strcmp(target_str, "next sibling") == 0)
|
|
|
- return TBSkinCondition::TARGET_NEXT_SIBLING;
|
|
|
- TBDebugOut("Skin error: Unknown target in condition!\n");
|
|
|
- return TBSkinCondition::TARGET_THIS;
|
|
|
+ if (strcmp(target_str, "this") == 0)
|
|
|
+ return TBSkinCondition::TARGET_THIS;
|
|
|
+ else if (strcmp(target_str, "parent") == 0)
|
|
|
+ return TBSkinCondition::TARGET_PARENT;
|
|
|
+ else if (strcmp(target_str, "ancestors") == 0)
|
|
|
+ return TBSkinCondition::TARGET_ANCESTORS;
|
|
|
+ else if (strcmp(target_str, "prev sibling") == 0)
|
|
|
+ return TBSkinCondition::TARGET_PREV_SIBLING;
|
|
|
+ else if (strcmp(target_str, "next sibling") == 0)
|
|
|
+ return TBSkinCondition::TARGET_NEXT_SIBLING;
|
|
|
+ TBDebugOut("Skin error: Unknown target in condition!\n");
|
|
|
+ return TBSkinCondition::TARGET_THIS;
|
|
|
}
|
|
|
|
|
|
TBSkinCondition::PROPERTY StringToProperty(const char *prop_str)
|
|
|
{
|
|
|
- if (strcmp(prop_str, "skin") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_SKIN;
|
|
|
- else if (strcmp(prop_str, "window active") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_WINDOW_ACTIVE;
|
|
|
- else if (strcmp(prop_str, "axis") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_AXIS;
|
|
|
- else if (strcmp(prop_str, "align") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_ALIGN;
|
|
|
- else if (strcmp(prop_str, "id") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_ID;
|
|
|
- else if (strcmp(prop_str, "state") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_STATE;
|
|
|
- else if (strcmp(prop_str, "value") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_VALUE;
|
|
|
- else if (strcmp(prop_str, "hover") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_HOVER;
|
|
|
- else if (strcmp(prop_str, "capture") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_CAPTURE;
|
|
|
- else if (strcmp(prop_str, "focus") == 0)
|
|
|
- return TBSkinCondition::PROPERTY_FOCUS;
|
|
|
- return TBSkinCondition::PROPERTY_CUSTOM;
|
|
|
+ if (strcmp(prop_str, "skin") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_SKIN;
|
|
|
+ else if (strcmp(prop_str, "window active") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_WINDOW_ACTIVE;
|
|
|
+ else if (strcmp(prop_str, "axis") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_AXIS;
|
|
|
+ else if (strcmp(prop_str, "align") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_ALIGN;
|
|
|
+ else if (strcmp(prop_str, "id") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_ID;
|
|
|
+ else if (strcmp(prop_str, "state") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_STATE;
|
|
|
+ else if (strcmp(prop_str, "value") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_VALUE;
|
|
|
+ else if (strcmp(prop_str, "hover") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_HOVER;
|
|
|
+ else if (strcmp(prop_str, "capture") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_CAPTURE;
|
|
|
+ else if (strcmp(prop_str, "focus") == 0)
|
|
|
+ return TBSkinCondition::PROPERTY_FOCUS;
|
|
|
+ return TBSkinCondition::PROPERTY_CUSTOM;
|
|
|
}
|
|
|
|
|
|
// == TBSkinCondition =======================================================
|
|
|
|
|
|
TBSkinCondition::TBSkinCondition(TARGET target, PROPERTY prop, const TBID &custom_prop, const TBID &value, TEST test)
|
|
|
- : m_target(target)
|
|
|
- , m_test(test)
|
|
|
+ : m_target(target)
|
|
|
+ , m_test(test)
|
|
|
{
|
|
|
- m_info.prop = prop;
|
|
|
- m_info.custom_prop = custom_prop;
|
|
|
- m_info.value = value;
|
|
|
+ m_info.prop = prop;
|
|
|
+ m_info.custom_prop = custom_prop;
|
|
|
+ m_info.value = value;
|
|
|
}
|
|
|
|
|
|
bool TBSkinCondition::GetCondition(TBSkinConditionContext &context) const
|
|
|
{
|
|
|
- bool equal = context.GetCondition(m_target, m_info);
|
|
|
- return equal == (m_test == TEST_EQUAL);
|
|
|
+ bool equal = context.GetCondition(m_target, m_info);
|
|
|
+ return equal == (m_test == TEST_EQUAL);
|
|
|
}
|
|
|
|
|
|
// == TBSkin ================================================================
|
|
|
|
|
|
TBSkin::TBSkin()
|
|
|
- : m_listener(nullptr)
|
|
|
- , m_default_disabled_opacity(0.3f)
|
|
|
- , m_default_placeholder_opacity(0.2f)
|
|
|
- , m_default_spacing(0)
|
|
|
+ : m_listener(nullptr)
|
|
|
+ , m_default_disabled_opacity(0.3f)
|
|
|
+ , m_default_placeholder_opacity(0.2f)
|
|
|
+ , m_default_spacing(0)
|
|
|
{
|
|
|
- g_renderer->AddListener(this);
|
|
|
+ g_renderer->AddListener(this);
|
|
|
|
|
|
- // Avoid filtering artifacts at edges when we draw fragments stretched.
|
|
|
- m_frag_manager.SetAddBorder(true);
|
|
|
+ // Avoid filtering artifacts at edges when we draw fragments stretched.
|
|
|
+ m_frag_manager.SetAddBorder(true);
|
|
|
}
|
|
|
|
|
|
bool TBSkin::Load(const char *skin_file, const char *override_skin_file)
|
|
|
{
|
|
|
- if (!LoadInternal(skin_file))
|
|
|
- return false;
|
|
|
+ if (!LoadInternal(skin_file))
|
|
|
+ return false;
|
|
|
if (override_skin_file && strlen(override_skin_file) && !LoadInternal(override_skin_file))
|
|
|
- return false;
|
|
|
- return ReloadBitmaps();
|
|
|
+ return false;
|
|
|
+ return ReloadBitmaps();
|
|
|
}
|
|
|
|
|
|
bool TBSkin::LoadInternal(const char *skin_file)
|
|
|
{
|
|
|
- TBNode node;
|
|
|
- if (!node.ReadFile(skin_file))
|
|
|
- return false;
|
|
|
-
|
|
|
- TBTempBuffer skin_path;
|
|
|
- if (!skin_path.AppendPath(skin_file))
|
|
|
- return false;
|
|
|
-
|
|
|
- if (node.GetNode("description"))
|
|
|
- {
|
|
|
- // Check which DPI mode the dimension converter should use.
|
|
|
- // The base-dpi is the dpi in which the padding, spacing (and so on)
|
|
|
- // is specified in. If the skin supports a different DPI that is
|
|
|
- // closer to the screen DPI, all such dimensions will be scaled.
|
|
|
- int base_dpi = node.GetValueInt("description>base-dpi", 96);
|
|
|
- int supported_dpi = base_dpi;
|
|
|
- if (TBNode *supported_dpi_node = node.GetNode("description>supported-dpi"))
|
|
|
- {
|
|
|
- assert(supported_dpi_node->GetValue().IsArray() || supported_dpi_node->GetValue().GetInt() == base_dpi);
|
|
|
- if (TBValueArray *arr = supported_dpi_node->GetValue().GetArray())
|
|
|
- {
|
|
|
- int screen_dpi = TBSystem::GetDPI();
|
|
|
- int best_supported_dpi = 0;
|
|
|
- for (int i = 0; i < arr->GetLength(); i++)
|
|
|
- {
|
|
|
- int candidate_dpi = arr->GetValue(i)->GetInt();
|
|
|
- if (!best_supported_dpi || ABS(candidate_dpi - screen_dpi) < ABS(best_supported_dpi - screen_dpi))
|
|
|
- best_supported_dpi = candidate_dpi;
|
|
|
- }
|
|
|
- supported_dpi = best_supported_dpi;
|
|
|
- }
|
|
|
- }
|
|
|
- m_dim_conv.SetDPI(base_dpi, supported_dpi);
|
|
|
- }
|
|
|
-
|
|
|
- // Read skin constants
|
|
|
- if (const char *color = node.GetValueString("defaults>text-color", nullptr))
|
|
|
- m_default_text_color.SetFromString(color, strlen(color));
|
|
|
- m_default_disabled_opacity = node.GetValueFloat("defaults>disabled>opacity",
|
|
|
- m_default_disabled_opacity);
|
|
|
- m_default_placeholder_opacity = node.GetValueFloat("defaults>placeholder>opacity",
|
|
|
- m_default_placeholder_opacity);
|
|
|
- m_default_spacing = GetPxFromNode(node.GetNode("defaults>spacing"), m_default_spacing);
|
|
|
-
|
|
|
- // Iterate through all elements nodes and add skin elements or patch already
|
|
|
- // existing elements.
|
|
|
- TBNode *elements = node.GetNode("elements");
|
|
|
- if (elements)
|
|
|
- {
|
|
|
- TBNode *n = elements->GetFirstChild();
|
|
|
- while (n)
|
|
|
- {
|
|
|
- // If we have a "clone" node, clone all children from that node
|
|
|
- // into this node.
|
|
|
- while (TBNode *clone = n->GetNode("clone"))
|
|
|
- {
|
|
|
- n->Remove(clone);
|
|
|
-
|
|
|
- TBNode *clone_source = elements->GetNode(clone->GetValue().GetString());
|
|
|
- if (clone_source)
|
|
|
- n->CloneChildren(clone_source);
|
|
|
-
|
|
|
- delete clone;
|
|
|
- }
|
|
|
-
|
|
|
- // If the skin element already exist, we will call Load on it again.
|
|
|
- // This will patch the element with any new data from the node.
|
|
|
- TBID element_id(n->GetName());
|
|
|
- TBSkinElement *e = GetSkinElement(element_id);
|
|
|
- if (!e)
|
|
|
- {
|
|
|
- e = new TBSkinElement;
|
|
|
- if (!e)
|
|
|
- return false;
|
|
|
- m_elements.Add(element_id, e);
|
|
|
- }
|
|
|
-
|
|
|
- e->Load(n, this, skin_path.GetData());
|
|
|
- if (m_listener)
|
|
|
- m_listener->OnSkinElementLoaded(this, e, n);
|
|
|
-
|
|
|
- n = n->GetNext();
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
+ TBNode node;
|
|
|
+ if (!node.ReadFile(skin_file))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ TBTempBuffer skin_path;
|
|
|
+ if (!skin_path.AppendPath(skin_file))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (node.GetNode("description"))
|
|
|
+ {
|
|
|
+ // Check which DPI mode the dimension converter should use.
|
|
|
+ // The base-dpi is the dpi in which the padding, spacing (and so on)
|
|
|
+ // is specified in. If the skin supports a different DPI that is
|
|
|
+ // closer to the screen DPI, all such dimensions will be scaled.
|
|
|
+ int base_dpi = node.GetValueInt("description>base-dpi", 96);
|
|
|
+ int supported_dpi = base_dpi;
|
|
|
+ if (TBNode *supported_dpi_node = node.GetNode("description>supported-dpi"))
|
|
|
+ {
|
|
|
+ assert(supported_dpi_node->GetValue().IsArray() || supported_dpi_node->GetValue().GetInt() == base_dpi);
|
|
|
+ if (TBValueArray *arr = supported_dpi_node->GetValue().GetArray())
|
|
|
+ {
|
|
|
+ int screen_dpi = TBSystem::GetDPI();
|
|
|
+ int best_supported_dpi = 0;
|
|
|
+ for (int i = 0; i < arr->GetLength(); i++)
|
|
|
+ {
|
|
|
+ int candidate_dpi = arr->GetValue(i)->GetInt();
|
|
|
+ if (!best_supported_dpi || ABS(candidate_dpi - screen_dpi) < ABS(best_supported_dpi - screen_dpi))
|
|
|
+ best_supported_dpi = candidate_dpi;
|
|
|
+ }
|
|
|
+ supported_dpi = best_supported_dpi;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ m_dim_conv.SetDPI(base_dpi, supported_dpi);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read skin constants
|
|
|
+ if (const char *color = node.GetValueString("defaults>text-color", nullptr))
|
|
|
+ m_default_text_color.SetFromString(color, strlen(color));
|
|
|
+ m_default_disabled_opacity = node.GetValueFloat("defaults>disabled>opacity",
|
|
|
+ m_default_disabled_opacity);
|
|
|
+ m_default_placeholder_opacity = node.GetValueFloat("defaults>placeholder>opacity",
|
|
|
+ m_default_placeholder_opacity);
|
|
|
+ m_default_spacing = GetPxFromNode(node.GetNode("defaults>spacing"), m_default_spacing);
|
|
|
+
|
|
|
+ // Iterate through all elements nodes and add skin elements or patch already
|
|
|
+ // existing elements.
|
|
|
+ TBNode *elements = node.GetNode("elements");
|
|
|
+ if (elements)
|
|
|
+ {
|
|
|
+ TBNode *n = elements->GetFirstChild();
|
|
|
+ while (n)
|
|
|
+ {
|
|
|
+ // If we have a "clone" node, clone all children from that node
|
|
|
+ // into this node.
|
|
|
+ while (TBNode *clone = n->GetNode("clone"))
|
|
|
+ {
|
|
|
+ n->Remove(clone);
|
|
|
+
|
|
|
+ TBNode *clone_source = elements->GetNode(clone->GetValue().GetString());
|
|
|
+ if (clone_source)
|
|
|
+ n->CloneChildren(clone_source);
|
|
|
+
|
|
|
+ delete clone;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the skin element already exist, we will call Load on it again.
|
|
|
+ // This will patch the element with any new data from the node.
|
|
|
+ TBID element_id(n->GetName());
|
|
|
+ TBSkinElement *e = GetSkinElement(element_id);
|
|
|
+ if (!e)
|
|
|
+ {
|
|
|
+ e = new TBSkinElement;
|
|
|
+ if (!e)
|
|
|
+ return false;
|
|
|
+ m_elements.Add(element_id, e);
|
|
|
+ }
|
|
|
+
|
|
|
+ e->Load(n, this, skin_path.GetData());
|
|
|
+ if (m_listener)
|
|
|
+ m_listener->OnSkinElementLoaded(this, e, n);
|
|
|
+
|
|
|
+ n = n->GetNext();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
void TBSkin::UnloadBitmaps()
|
|
|
{
|
|
|
- // Unset all bitmap pointers.
|
|
|
- TBHashTableIteratorOf<TBSkinElement> it(&m_elements);
|
|
|
- while (TBSkinElement *element = it.GetNextContent())
|
|
|
- element->bitmap = nullptr;
|
|
|
+ // Unset all bitmap pointers.
|
|
|
+ TBHashTableIteratorOf<TBSkinElement> it(&m_elements);
|
|
|
+ while (TBSkinElement *element = it.GetNextContent())
|
|
|
+ element->bitmap = nullptr;
|
|
|
|
|
|
- // Clear all fragments and bitmaps.
|
|
|
- m_frag_manager.Clear();
|
|
|
+ // Clear all fragments and bitmaps.
|
|
|
+ m_frag_manager.Clear();
|
|
|
}
|
|
|
|
|
|
bool TBSkin::ReloadBitmaps()
|
|
|
{
|
|
|
- UnloadBitmaps();
|
|
|
- bool success = ReloadBitmapsInternal();
|
|
|
- // Create all bitmaps for the bitmap fragment maps
|
|
|
- if (success)
|
|
|
- success = m_frag_manager.ValidateBitmaps();
|
|
|
+ UnloadBitmaps();
|
|
|
+ bool success = ReloadBitmapsInternal();
|
|
|
+ // Create all bitmaps for the bitmap fragment maps
|
|
|
+ if (success)
|
|
|
+ success = m_frag_manager.ValidateBitmaps();
|
|
|
|
|
|
#ifdef TB_RUNTIME_DEBUG_INFO
|
|
|
- TBStr info;
|
|
|
- info.SetFormatted("Skin loaded using %d bitmaps.\n", m_frag_manager.GetNumMaps());
|
|
|
- TBDebugOut(info);
|
|
|
+ TBStr info;
|
|
|
+ info.SetFormatted("Skin loaded using %d bitmaps.\n", m_frag_manager.GetNumMaps());
|
|
|
+ TBDebugOut(info);
|
|
|
#endif
|
|
|
- return success;
|
|
|
+ return success;
|
|
|
}
|
|
|
|
|
|
bool TBSkin::ReloadBitmapsInternal()
|
|
|
{
|
|
|
- // Load all bitmap files into new bitmap fragments.
|
|
|
- TBTempBuffer filename_dst_DPI;
|
|
|
- bool success = true;
|
|
|
- TBHashTableIteratorOf<TBSkinElement> it(&m_elements);
|
|
|
- while (TBSkinElement *element = it.GetNextContent())
|
|
|
- {
|
|
|
- if (!element->bitmap_file.IsEmpty())
|
|
|
- {
|
|
|
- assert(!element->bitmap);
|
|
|
-
|
|
|
- // FIX: dedicated_map is not needed for all backends (only deprecated fixed function GL)
|
|
|
- bool dedicated_map = element->type == SKIN_ELEMENT_TYPE_TILE;
|
|
|
-
|
|
|
- // Try to load bitmap fragment in the destination DPI (F.ex "foo.png" becomes "[email protected]")
|
|
|
- int bitmap_dpi = m_dim_conv.GetSrcDPI();
|
|
|
- if (m_dim_conv.NeedConversion())
|
|
|
- {
|
|
|
- m_dim_conv.GetDstDPIFilename(element->bitmap_file, &filename_dst_DPI);
|
|
|
- element->bitmap = m_frag_manager.GetFragmentFromFile(filename_dst_DPI.GetData(), dedicated_map);
|
|
|
- if (element->bitmap)
|
|
|
- bitmap_dpi = m_dim_conv.GetDstDPI();
|
|
|
- }
|
|
|
- element->SetBitmapDPI(m_dim_conv, bitmap_dpi);
|
|
|
-
|
|
|
- // If we still have no bitmap fragment, load from default file.
|
|
|
- if (!element->bitmap)
|
|
|
- element->bitmap = m_frag_manager.GetFragmentFromFile(element->bitmap_file, dedicated_map);
|
|
|
-
|
|
|
- if (!element->bitmap)
|
|
|
- success = false;
|
|
|
- }
|
|
|
- }
|
|
|
- return success;
|
|
|
+ // Load all bitmap files into new bitmap fragments.
|
|
|
+ TBTempBuffer filename_dst_DPI;
|
|
|
+ bool success = true;
|
|
|
+ TBHashTableIteratorOf<TBSkinElement> it(&m_elements);
|
|
|
+ while (TBSkinElement *element = it.GetNextContent())
|
|
|
+ {
|
|
|
+ if (!element->bitmap_file.IsEmpty())
|
|
|
+ {
|
|
|
+ assert(!element->bitmap);
|
|
|
+
|
|
|
+ // FIX: dedicated_map is not needed for all backends (only deprecated fixed function GL)
|
|
|
+ bool dedicated_map = element->type == SKIN_ELEMENT_TYPE_TILE;
|
|
|
+
|
|
|
+ // Try to load bitmap fragment in the destination DPI (F.ex "foo.png" becomes "[email protected]")
|
|
|
+ int bitmap_dpi = m_dim_conv.GetSrcDPI();
|
|
|
+ if (m_dim_conv.NeedConversion())
|
|
|
+ {
|
|
|
+ m_dim_conv.GetDstDPIFilename(element->bitmap_file, &filename_dst_DPI);
|
|
|
+ element->bitmap = m_frag_manager.GetFragmentFromFile(filename_dst_DPI.GetData(), dedicated_map);
|
|
|
+ if (element->bitmap)
|
|
|
+ bitmap_dpi = m_dim_conv.GetDstDPI();
|
|
|
+ }
|
|
|
+ element->SetBitmapDPI(m_dim_conv, bitmap_dpi);
|
|
|
+
|
|
|
+ // If we still have no bitmap fragment, load from default file.
|
|
|
+ if (!element->bitmap)
|
|
|
+ element->bitmap = m_frag_manager.GetFragmentFromFile(element->bitmap_file, dedicated_map);
|
|
|
+
|
|
|
+ if (!element->bitmap)
|
|
|
+ success = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return success;
|
|
|
}
|
|
|
|
|
|
TBSkin::~TBSkin()
|
|
|
{
|
|
|
- g_renderer->RemoveListener(this);
|
|
|
+ g_renderer->RemoveListener(this);
|
|
|
}
|
|
|
|
|
|
TBSkinElement *TBSkin::GetSkinElement(const TBID &skin_id) const
|
|
|
{
|
|
|
- if (!skin_id)
|
|
|
- return nullptr;
|
|
|
- return m_elements.Get(skin_id);
|
|
|
+ if (!skin_id)
|
|
|
+ return nullptr;
|
|
|
+ return m_elements.Get(skin_id);
|
|
|
}
|
|
|
|
|
|
TBSkinElement *TBSkin::GetSkinElementStrongOverride(const TBID &skin_id, SKIN_STATE state, TBSkinConditionContext &context) const
|
|
|
{
|
|
|
- if (TBSkinElement *skin_element = GetSkinElement(skin_id))
|
|
|
- {
|
|
|
- // Avoid eternal recursion when overrides refer to elements referring back.
|
|
|
- if (skin_element->is_getting)
|
|
|
- return nullptr;
|
|
|
- skin_element->is_getting = true;
|
|
|
-
|
|
|
- // Check if there's any strong overrides for this element with the given state.
|
|
|
- TBSkinElementState *override_state = skin_element->m_strong_override_elements.GetStateElement(state, context);
|
|
|
- if (override_state)
|
|
|
- {
|
|
|
- if (TBSkinElement *override_element = GetSkinElementStrongOverride(override_state->element_id, state, context))
|
|
|
- {
|
|
|
- skin_element->is_getting = false;
|
|
|
- return override_element;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- skin_element->is_getting = false;
|
|
|
- return skin_element;
|
|
|
- }
|
|
|
- return nullptr;
|
|
|
+ if (TBSkinElement *skin_element = GetSkinElement(skin_id))
|
|
|
+ {
|
|
|
+ // Avoid eternal recursion when overrides refer to elements referring back.
|
|
|
+ if (skin_element->is_getting)
|
|
|
+ return nullptr;
|
|
|
+ skin_element->is_getting = true;
|
|
|
+
|
|
|
+ // Check if there's any strong overrides for this element with the given state.
|
|
|
+ TBSkinElementState *override_state = skin_element->m_strong_override_elements.GetStateElement(state, context);
|
|
|
+ if (override_state)
|
|
|
+ {
|
|
|
+ if (TBSkinElement *override_element = GetSkinElementStrongOverride(override_state->element_id, state, context))
|
|
|
+ {
|
|
|
+ skin_element->is_getting = false;
|
|
|
+ return override_element;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ skin_element->is_getting = false;
|
|
|
+ return skin_element;
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
TBSkinElement *TBSkin::PaintSkin(const TBRect &dst_rect, const TBID &skin_id, SKIN_STATE state, TBSkinConditionContext &context)
|
|
|
{
|
|
|
- return PaintSkin(dst_rect, GetSkinElement(skin_id), state, context);
|
|
|
+ return PaintSkin(dst_rect, GetSkinElement(skin_id), state, context);
|
|
|
}
|
|
|
|
|
|
TBSkinElement *TBSkin::PaintSkin(const TBRect &dst_rect, TBSkinElement *element, SKIN_STATE state, TBSkinConditionContext &context)
|
|
|
{
|
|
|
- if (!element || element->is_painting)
|
|
|
- return nullptr;
|
|
|
-
|
|
|
- // Avoid potential endless recursion in evil skins
|
|
|
- element->is_painting = true;
|
|
|
-
|
|
|
- // Return the override if we have one.
|
|
|
- TBSkinElement *return_element = element;
|
|
|
-
|
|
|
- TB_IF_DEBUG(bool paint_error_highlight = false);
|
|
|
-
|
|
|
- // If there's any override for this state, paint it.
|
|
|
- TBSkinElementState *override_state = element->m_override_elements.GetStateElement(state, context);
|
|
|
- if (override_state)
|
|
|
- {
|
|
|
- if (TBSkinElement *used_override = PaintSkin(dst_rect, override_state->element_id, state, context))
|
|
|
- return_element = used_override;
|
|
|
- else
|
|
|
- {
|
|
|
- TB_IF_DEBUG(paint_error_highlight = true);
|
|
|
- TBDebugOut("Skin error: The skin references a missing element, or has a reference loop!\n");
|
|
|
- // Fall back to the standard skin.
|
|
|
- override_state = nullptr;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // If there was no override, paint the standard skin element.
|
|
|
- if (!override_state)
|
|
|
- PaintElement(dst_rect, element);
|
|
|
-
|
|
|
- // Paint all child elements that matches the state (or should be painted for all states)
|
|
|
- if (element->m_child_elements.HasStateElements())
|
|
|
- {
|
|
|
- const TBSkinElementState *state_element = element->m_child_elements.GetFirstElement();
|
|
|
- while (state_element)
|
|
|
- {
|
|
|
- if (state_element->IsMatch(state, context))
|
|
|
- PaintSkin(dst_rect, state_element->element_id, state_element->state & state, context);
|
|
|
- state_element = state_element->GetNext();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Paint ugly rectangles on invalid skin elements in debug builds.
|
|
|
- TB_IF_DEBUG(if (paint_error_highlight) g_renderer->DrawRect(dst_rect.Expand(1, 1), TBColor(255, 205, 0)));
|
|
|
- TB_IF_DEBUG(if (paint_error_highlight) g_renderer->DrawRect(dst_rect.Shrink(1, 1), TBColor(255, 0, 0)));
|
|
|
-
|
|
|
- element->is_painting = false;
|
|
|
- return return_element;
|
|
|
+ if (!element || element->is_painting)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ // Avoid potential endless recursion in evil skins
|
|
|
+ element->is_painting = true;
|
|
|
+
|
|
|
+ // Return the override if we have one.
|
|
|
+ TBSkinElement *return_element = element;
|
|
|
+
|
|
|
+ TB_IF_DEBUG(bool paint_error_highlight = false);
|
|
|
+
|
|
|
+ // If there's any override for this state, paint it.
|
|
|
+ TBSkinElementState *override_state = element->m_override_elements.GetStateElement(state, context);
|
|
|
+ if (override_state)
|
|
|
+ {
|
|
|
+ if (TBSkinElement *used_override = PaintSkin(dst_rect, override_state->element_id, state, context))
|
|
|
+ return_element = used_override;
|
|
|
+ else
|
|
|
+ {
|
|
|
+ TB_IF_DEBUG(paint_error_highlight = true);
|
|
|
+ TBDebugOut("Skin error: The skin references a missing element, or has a reference loop!\n");
|
|
|
+ // Fall back to the standard skin.
|
|
|
+ override_state = nullptr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // If there was no override, paint the standard skin element.
|
|
|
+ if (!override_state)
|
|
|
+ PaintElement(dst_rect, element);
|
|
|
+
|
|
|
+ // Paint all child elements that matches the state (or should be painted for all states)
|
|
|
+ if (element->m_child_elements.HasStateElements())
|
|
|
+ {
|
|
|
+ const TBSkinElementState *state_element = element->m_child_elements.GetFirstElement();
|
|
|
+ while (state_element)
|
|
|
+ {
|
|
|
+ if (state_element->IsMatch(state, context))
|
|
|
+ PaintSkin(dst_rect, state_element->element_id, state_element->state & state, context);
|
|
|
+ state_element = state_element->GetNext();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Paint ugly rectangles on invalid skin elements in debug builds.
|
|
|
+ TB_IF_DEBUG(if (paint_error_highlight) g_renderer->DrawRect(dst_rect.Expand(1, 1), TBColor(255, 205, 0)));
|
|
|
+ TB_IF_DEBUG(if (paint_error_highlight) g_renderer->DrawRect(dst_rect.Shrink(1, 1), TBColor(255, 0, 0)));
|
|
|
+
|
|
|
+ element->is_painting = false;
|
|
|
+ return return_element;
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintSkinOverlay(const TBRect &dst_rect, TBSkinElement *element, SKIN_STATE state, TBSkinConditionContext &context)
|
|
|
{
|
|
|
- if (!element || element->is_painting)
|
|
|
- return;
|
|
|
+ if (!element || element->is_painting)
|
|
|
+ return;
|
|
|
|
|
|
- // Avoid potential endless recursion in evil skins
|
|
|
- element->is_painting = true;
|
|
|
+ // Avoid potential endless recursion in evil skins
|
|
|
+ element->is_painting = true;
|
|
|
|
|
|
- // Paint all overlay elements that matches the state (or should be painted for all states)
|
|
|
- const TBSkinElementState *state_element = element->m_overlay_elements.GetFirstElement();
|
|
|
- while (state_element)
|
|
|
- {
|
|
|
- if (state_element->IsMatch(state, context))
|
|
|
- PaintSkin(dst_rect, state_element->element_id, state_element->state & state, context);
|
|
|
- state_element = state_element->GetNext();
|
|
|
- }
|
|
|
+ // Paint all overlay elements that matches the state (or should be painted for all states)
|
|
|
+ const TBSkinElementState *state_element = element->m_overlay_elements.GetFirstElement();
|
|
|
+ while (state_element)
|
|
|
+ {
|
|
|
+ if (state_element->IsMatch(state, context))
|
|
|
+ PaintSkin(dst_rect, state_element->element_id, state_element->state & state, context);
|
|
|
+ state_element = state_element->GetNext();
|
|
|
+ }
|
|
|
|
|
|
- element->is_painting = false;
|
|
|
+ element->is_painting = false;
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintElement(const TBRect &dst_rect, TBSkinElement *element)
|
|
|
{
|
|
|
- PaintElementBGColor(dst_rect, element);
|
|
|
- if (!element->bitmap)
|
|
|
- return;
|
|
|
- if (element->type == SKIN_ELEMENT_TYPE_IMAGE)
|
|
|
- PaintElementImage(dst_rect, element);
|
|
|
- else if (element->type == SKIN_ELEMENT_TYPE_TILE)
|
|
|
- PaintElementTile(dst_rect, element);
|
|
|
- else if (element->type == SKIN_ELEMENT_TYPE_STRETCH_IMAGE || element->cut == 0)
|
|
|
- PaintElementStretchImage(dst_rect, element);
|
|
|
- else if (element->type == SKIN_ELEMENT_TYPE_STRETCH_BORDER)
|
|
|
- PaintElementStretchBox(dst_rect, element, false);
|
|
|
- else
|
|
|
- PaintElementStretchBox(dst_rect, element, true);
|
|
|
+ PaintElementBGColor(dst_rect, element);
|
|
|
+ if (!element->bitmap)
|
|
|
+ return;
|
|
|
+ if (element->type == SKIN_ELEMENT_TYPE_IMAGE)
|
|
|
+ PaintElementImage(dst_rect, element);
|
|
|
+ else if (element->type == SKIN_ELEMENT_TYPE_TILE)
|
|
|
+ PaintElementTile(dst_rect, element);
|
|
|
+ else if (element->type == SKIN_ELEMENT_TYPE_STRETCH_IMAGE || element->cut == 0)
|
|
|
+ PaintElementStretchImage(dst_rect, element);
|
|
|
+ else if (element->type == SKIN_ELEMENT_TYPE_STRETCH_BORDER)
|
|
|
+ PaintElementStretchBox(dst_rect, element, false);
|
|
|
+ else
|
|
|
+ PaintElementStretchBox(dst_rect, element, true);
|
|
|
}
|
|
|
|
|
|
TBRect TBSkin::GetFlippedRect(const TBRect &src_rect, TBSkinElement *element) const
|
|
|
{
|
|
|
- // Turning the source rect "inside out" will flip the result when rendered.
|
|
|
- TBRect tmp_rect = src_rect;
|
|
|
- if (element->flip_x)
|
|
|
- {
|
|
|
- tmp_rect.x += tmp_rect.w;
|
|
|
- tmp_rect.w = -tmp_rect.w;
|
|
|
- }
|
|
|
- if (element->flip_y)
|
|
|
- {
|
|
|
- tmp_rect.y += tmp_rect.h;
|
|
|
- tmp_rect.h = -tmp_rect.h;
|
|
|
- }
|
|
|
- return tmp_rect;
|
|
|
+ // Turning the source rect "inside out" will flip the result when rendered.
|
|
|
+ TBRect tmp_rect = src_rect;
|
|
|
+ if (element->flip_x)
|
|
|
+ {
|
|
|
+ tmp_rect.x += tmp_rect.w;
|
|
|
+ tmp_rect.w = -tmp_rect.w;
|
|
|
+ }
|
|
|
+ if (element->flip_y)
|
|
|
+ {
|
|
|
+ tmp_rect.y += tmp_rect.h;
|
|
|
+ tmp_rect.h = -tmp_rect.h;
|
|
|
+ }
|
|
|
+ return tmp_rect;
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintElementBGColor(const TBRect &dst_rect, TBSkinElement *element)
|
|
|
{
|
|
|
- if (element->bg_color == 0)
|
|
|
- return;
|
|
|
- g_renderer->DrawRectFill(dst_rect, element->bg_color);
|
|
|
+ if (element->bg_color == 0)
|
|
|
+ return;
|
|
|
+ g_renderer->DrawRectFill(dst_rect, element->bg_color);
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintElementImage(const TBRect &dst_rect, TBSkinElement *element)
|
|
|
{
|
|
|
- TBRect src_rect(0, 0, element->bitmap->Width(), element->bitmap->Height());
|
|
|
- TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
- rect.Set(rect.x + element->img_ofs_x + (rect.w - src_rect.w) * element->img_position_x / 100,
|
|
|
- rect.y + element->img_ofs_y + (rect.h - src_rect.h) * element->img_position_y / 100,
|
|
|
- src_rect.w, src_rect.h);
|
|
|
- g_renderer->DrawBitmap(rect, GetFlippedRect(src_rect, element), element->bitmap);
|
|
|
+ TBRect src_rect(0, 0, element->bitmap->Width(), element->bitmap->Height());
|
|
|
+ TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
+ rect.Set(rect.x + element->img_ofs_x + (rect.w - src_rect.w) * element->img_position_x / 100,
|
|
|
+ rect.y + element->img_ofs_y + (rect.h - src_rect.h) * element->img_position_y / 100,
|
|
|
+ src_rect.w, src_rect.h);
|
|
|
+ g_renderer->DrawBitmap(rect, GetFlippedRect(src_rect, element), element->bitmap);
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintElementTile(const TBRect &dst_rect, TBSkinElement *element)
|
|
|
{
|
|
|
- TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
- g_renderer->DrawBitmapTile(rect, element->bitmap->GetBitmap());
|
|
|
+ TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
+ g_renderer->DrawBitmapTile(rect, element->bitmap->GetBitmap());
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintElementStretchImage(const TBRect &dst_rect, TBSkinElement *element)
|
|
|
{
|
|
|
- if (dst_rect.IsEmpty())
|
|
|
- return;
|
|
|
- TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
- TBRect src_rect = GetFlippedRect(TBRect(0, 0, element->bitmap->Width(), element->bitmap->Height()), element);
|
|
|
- g_renderer->DrawBitmap(rect, src_rect, element->bitmap);
|
|
|
+ if (dst_rect.IsEmpty())
|
|
|
+ return;
|
|
|
+ TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
+ TBRect src_rect = GetFlippedRect(TBRect(0, 0, element->bitmap->Width(), element->bitmap->Height()), element);
|
|
|
+ g_renderer->DrawBitmap(rect, src_rect, element->bitmap);
|
|
|
}
|
|
|
|
|
|
void TBSkin::PaintElementStretchBox(const TBRect &dst_rect, TBSkinElement *element, bool fill_center)
|
|
|
{
|
|
|
- if (dst_rect.IsEmpty())
|
|
|
- return;
|
|
|
-
|
|
|
- TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
-
|
|
|
- // Stretch the dst_cut (if rect is smaller than the skin size)
|
|
|
- // FIX: the expand should also be stretched!
|
|
|
- int cut = element->cut;
|
|
|
- int dst_cut_w = MIN(cut, rect.w / 2);
|
|
|
- int dst_cut_h = MIN(cut, rect.h / 2);
|
|
|
- int bw = element->bitmap->Width();
|
|
|
- int bh = element->bitmap->Height();
|
|
|
-
|
|
|
- bool has_left_right_edges = rect.h > dst_cut_h * 2;
|
|
|
- bool has_top_bottom_edges = rect.w > dst_cut_w * 2;
|
|
|
-
|
|
|
- rect = GetFlippedRect(rect, element);
|
|
|
- if (element->flip_x)
|
|
|
- dst_cut_w = -dst_cut_w;
|
|
|
- if (element->flip_y)
|
|
|
- dst_cut_h = -dst_cut_h;
|
|
|
-
|
|
|
- // Corners
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x, rect.y, dst_cut_w, dst_cut_h), TBRect(0, 0, cut, cut), element->bitmap);
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x + rect.w - dst_cut_w, rect.y, dst_cut_w, dst_cut_h), TBRect(bw - cut, 0, cut, cut), element->bitmap);
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x, rect.y + rect.h - dst_cut_h, dst_cut_w, dst_cut_h), TBRect(0, bh - cut, cut, cut), element->bitmap);
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x + rect.w - dst_cut_w, rect.y + rect.h - dst_cut_h, dst_cut_w, dst_cut_h), TBRect(bw - cut, bh - cut, cut, cut), element->bitmap);
|
|
|
-
|
|
|
- // Left & right edge
|
|
|
- if (has_left_right_edges)
|
|
|
- {
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x, rect.y + dst_cut_h, dst_cut_w, rect.h - dst_cut_h * 2), TBRect(0, cut, cut, bh - cut * 2), element->bitmap);
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x + rect.w - dst_cut_w, rect.y + dst_cut_h, dst_cut_w, rect.h - dst_cut_h * 2), TBRect(bw - cut, cut, cut, bh - cut * 2), element->bitmap);
|
|
|
- }
|
|
|
-
|
|
|
- // Top & bottom edge
|
|
|
- if (has_top_bottom_edges)
|
|
|
- {
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x + dst_cut_w, rect.y, rect.w - dst_cut_w * 2, dst_cut_h), TBRect(cut, 0, bw - cut * 2, cut), element->bitmap);
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x + dst_cut_w, rect.y + rect.h - dst_cut_h, rect.w - dst_cut_w * 2, dst_cut_h), TBRect(cut, bh - cut, bw - cut * 2, cut), element->bitmap);
|
|
|
- }
|
|
|
-
|
|
|
- // Center
|
|
|
- if (fill_center && has_top_bottom_edges && has_left_right_edges)
|
|
|
- g_renderer->DrawBitmap(TBRect(rect.x + dst_cut_w, rect.y + dst_cut_h, rect.w - dst_cut_w * 2, rect.h - dst_cut_h * 2), TBRect(cut, cut, bw - cut * 2, bh - cut * 2), element->bitmap);
|
|
|
+ if (dst_rect.IsEmpty())
|
|
|
+ return;
|
|
|
+
|
|
|
+ TBRect rect = dst_rect.Expand(element->expand, element->expand);
|
|
|
+
|
|
|
+ // Stretch the dst_cut (if rect is smaller than the skin size)
|
|
|
+ // FIX: the expand should also be stretched!
|
|
|
+ int cut = element->cut;
|
|
|
+ int dst_cut_w = MIN(cut, rect.w / 2);
|
|
|
+ int dst_cut_h = MIN(cut, rect.h / 2);
|
|
|
+ int bw = element->bitmap->Width();
|
|
|
+ int bh = element->bitmap->Height();
|
|
|
+
|
|
|
+ bool has_left_right_edges = rect.h > dst_cut_h * 2;
|
|
|
+ bool has_top_bottom_edges = rect.w > dst_cut_w * 2;
|
|
|
+
|
|
|
+ rect = GetFlippedRect(rect, element);
|
|
|
+ if (element->flip_x)
|
|
|
+ dst_cut_w = -dst_cut_w;
|
|
|
+ if (element->flip_y)
|
|
|
+ dst_cut_h = -dst_cut_h;
|
|
|
+
|
|
|
+ // Corners
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x, rect.y, dst_cut_w, dst_cut_h), TBRect(0, 0, cut, cut), element->bitmap);
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x + rect.w - dst_cut_w, rect.y, dst_cut_w, dst_cut_h), TBRect(bw - cut, 0, cut, cut), element->bitmap);
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x, rect.y + rect.h - dst_cut_h, dst_cut_w, dst_cut_h), TBRect(0, bh - cut, cut, cut), element->bitmap);
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x + rect.w - dst_cut_w, rect.y + rect.h - dst_cut_h, dst_cut_w, dst_cut_h), TBRect(bw - cut, bh - cut, cut, cut), element->bitmap);
|
|
|
+
|
|
|
+ // Left & right edge
|
|
|
+ if (has_left_right_edges)
|
|
|
+ {
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x, rect.y + dst_cut_h, dst_cut_w, rect.h - dst_cut_h * 2), TBRect(0, cut, cut, bh - cut * 2), element->bitmap);
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x + rect.w - dst_cut_w, rect.y + dst_cut_h, dst_cut_w, rect.h - dst_cut_h * 2), TBRect(bw - cut, cut, cut, bh - cut * 2), element->bitmap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Top & bottom edge
|
|
|
+ if (has_top_bottom_edges)
|
|
|
+ {
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x + dst_cut_w, rect.y, rect.w - dst_cut_w * 2, dst_cut_h), TBRect(cut, 0, bw - cut * 2, cut), element->bitmap);
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x + dst_cut_w, rect.y + rect.h - dst_cut_h, rect.w - dst_cut_w * 2, dst_cut_h), TBRect(cut, bh - cut, bw - cut * 2, cut), element->bitmap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Center
|
|
|
+ if (fill_center && has_top_bottom_edges && has_left_right_edges)
|
|
|
+ g_renderer->DrawBitmap(TBRect(rect.x + dst_cut_w, rect.y + dst_cut_h, rect.w - dst_cut_w * 2, rect.h - dst_cut_h * 2), TBRect(cut, cut, bw - cut * 2, bh - cut * 2), element->bitmap);
|
|
|
}
|
|
|
|
|
|
#ifdef TB_RUNTIME_DEBUG_INFO
|
|
|
void TBSkin::Debug()
|
|
|
{
|
|
|
- m_frag_manager.Debug();
|
|
|
+ m_frag_manager.Debug();
|
|
|
}
|
|
|
#endif // TB_RUNTIME_DEBUG_INFO
|
|
|
|
|
|
void TBSkin::OnContextLost()
|
|
|
{
|
|
|
- // We could simply do: m_frag_manager.DeleteBitmaps() and then all bitmaps
|
|
|
- // would be recreated automatically when needed. But because it's easy,
|
|
|
- // we unload everything so we save some memory (by not keeping any image
|
|
|
- // data around).
|
|
|
- UnloadBitmaps();
|
|
|
+ // We could simply do: m_frag_manager.DeleteBitmaps() and then all bitmaps
|
|
|
+ // would be recreated automatically when needed. But because it's easy,
|
|
|
+ // we unload everything so we save some memory (by not keeping any image
|
|
|
+ // data around).
|
|
|
+ UnloadBitmaps();
|
|
|
}
|
|
|
|
|
|
void TBSkin::OnContextRestored()
|
|
|
{
|
|
|
- // Reload bitmaps (since we unloaded everything in OnContextLost())
|
|
|
- ReloadBitmaps();
|
|
|
+ // Reload bitmaps (since we unloaded everything in OnContextLost())
|
|
|
+ ReloadBitmaps();
|
|
|
}
|
|
|
|
|
|
int TBSkin::GetPxFromNode(TBNode *node, int def_value) const
|
|
|
{
|
|
|
- return node ? m_dim_conv.GetPxFromValue(&node->GetValue(), def_value) : def_value;
|
|
|
+ return node ? m_dim_conv.GetPxFromValue(&node->GetValue(), def_value) : def_value;
|
|
|
}
|
|
|
|
|
|
// == TBSkinElement =========================================================
|
|
|
|
|
|
TBSkinElement::TBSkinElement()
|
|
|
- : bitmap(nullptr), cut(0), expand(0), type(SKIN_ELEMENT_TYPE_STRETCH_BOX)
|
|
|
- , is_painting(false), is_getting(false)
|
|
|
- , padding_left(0), padding_top(0), padding_right(0), padding_bottom(0)
|
|
|
- , width(SKIN_VALUE_NOT_SPECIFIED), height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- , pref_width(SKIN_VALUE_NOT_SPECIFIED), pref_height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- , min_width(SKIN_VALUE_NOT_SPECIFIED), min_height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- , max_width(SKIN_VALUE_NOT_SPECIFIED), max_height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- , spacing(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- , content_ofs_x(0), content_ofs_y(0)
|
|
|
- , img_ofs_x(0), img_ofs_y(0)
|
|
|
- , img_position_x(50), img_position_y(50)
|
|
|
- , flip_x(0), flip_y(0), opacity(1.f)
|
|
|
- , text_color(0, 0, 0, 0)
|
|
|
- , bg_color(0, 0, 0, 0)
|
|
|
- , bitmap_dpi(0)
|
|
|
+ : bitmap(nullptr), cut(0), expand(0), type(SKIN_ELEMENT_TYPE_STRETCH_BOX)
|
|
|
+ , is_painting(false), is_getting(false)
|
|
|
+ , padding_left(0), padding_top(0), padding_right(0), padding_bottom(0)
|
|
|
+ , width(SKIN_VALUE_NOT_SPECIFIED), height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ , pref_width(SKIN_VALUE_NOT_SPECIFIED), pref_height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ , min_width(SKIN_VALUE_NOT_SPECIFIED), min_height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ , max_width(SKIN_VALUE_NOT_SPECIFIED), max_height(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ , spacing(SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ , content_ofs_x(0), content_ofs_y(0)
|
|
|
+ , img_ofs_x(0), img_ofs_y(0)
|
|
|
+ , img_position_x(50), img_position_y(50)
|
|
|
+ , flip_x(0), flip_y(0), opacity(1.f)
|
|
|
+ , text_color(0, 0, 0, 0)
|
|
|
+ , bg_color(0, 0, 0, 0)
|
|
|
+ , bitmap_dpi(0)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
@@ -570,279 +570,279 @@ TBSkinElement::~TBSkinElement()
|
|
|
|
|
|
int TBSkinElement::GetIntrinsicMinWidth() const
|
|
|
{
|
|
|
- // Sizes below the skin cut size would start to shrink the skin below pretty,
|
|
|
- // so assume that's the default minimum size if it's not specified (minus expansion)
|
|
|
- return cut * 2 - expand * 2;
|
|
|
+ // Sizes below the skin cut size would start to shrink the skin below pretty,
|
|
|
+ // so assume that's the default minimum size if it's not specified (minus expansion)
|
|
|
+ return cut * 2 - expand * 2;
|
|
|
}
|
|
|
|
|
|
int TBSkinElement::GetIntrinsicMinHeight() const
|
|
|
{
|
|
|
- // Sizes below the skin cut size would start to shrink the skin below pretty,
|
|
|
- // so assume that's the default minimum size if it's not specified (minus expansion)
|
|
|
- return cut * 2 - expand * 2;
|
|
|
+ // Sizes below the skin cut size would start to shrink the skin below pretty,
|
|
|
+ // so assume that's the default minimum size if it's not specified (minus expansion)
|
|
|
+ return cut * 2 - expand * 2;
|
|
|
}
|
|
|
|
|
|
int TBSkinElement::GetIntrinsicWidth() const
|
|
|
{
|
|
|
- if (width != SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- return width;
|
|
|
- if (bitmap)
|
|
|
- return bitmap->Width() - expand * 2;
|
|
|
- // FIX: We may want to check child elements etc.
|
|
|
- return SKIN_VALUE_NOT_SPECIFIED;
|
|
|
+ if (width != SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ return width;
|
|
|
+ if (bitmap)
|
|
|
+ return bitmap->Width() - expand * 2;
|
|
|
+ // FIX: We may want to check child elements etc.
|
|
|
+ return SKIN_VALUE_NOT_SPECIFIED;
|
|
|
}
|
|
|
|
|
|
int TBSkinElement::GetIntrinsicHeight() const
|
|
|
{
|
|
|
- if (height != SKIN_VALUE_NOT_SPECIFIED)
|
|
|
- return height;
|
|
|
- if (bitmap)
|
|
|
- return bitmap->Height() - expand * 2;
|
|
|
- // FIX: We may want to check child elements etc.
|
|
|
- return SKIN_VALUE_NOT_SPECIFIED;
|
|
|
+ if (height != SKIN_VALUE_NOT_SPECIFIED)
|
|
|
+ return height;
|
|
|
+ if (bitmap)
|
|
|
+ return bitmap->Height() - expand * 2;
|
|
|
+ // FIX: We may want to check child elements etc.
|
|
|
+ return SKIN_VALUE_NOT_SPECIFIED;
|
|
|
}
|
|
|
|
|
|
void TBSkinElement::SetBitmapDPI(const TBDimensionConverter &dim_conv, int bitmap_dpi)
|
|
|
{
|
|
|
- if (this->bitmap_dpi)
|
|
|
- {
|
|
|
- // We have already applied the modifications so abort. This may
|
|
|
- // happen when we reload bitmaps without reloading the skin.
|
|
|
- return;
|
|
|
- }
|
|
|
- if (dim_conv.NeedConversion())
|
|
|
- {
|
|
|
- if (bitmap_dpi == dim_conv.GetDstDPI())
|
|
|
- {
|
|
|
- // The bitmap was loaded in a different DPI than the base DPI so
|
|
|
- // we must scale the bitmap properties.
|
|
|
- expand = expand * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
- cut = cut * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // The bitmap was loaded in the base DPI and we need to scale it.
|
|
|
- // Apply the DPI conversion to the skin element scale factor.
|
|
|
- // FIX: For this to work well, we would need to apply scale to both
|
|
|
- // image and all the other types of drawing too.
|
|
|
- // scale_x = scale_x * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
- // scale_y = scale_y * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
- }
|
|
|
- }
|
|
|
- this->bitmap_dpi = bitmap_dpi;
|
|
|
+ if (this->bitmap_dpi)
|
|
|
+ {
|
|
|
+ // We have already applied the modifications so abort. This may
|
|
|
+ // happen when we reload bitmaps without reloading the skin.
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (dim_conv.NeedConversion())
|
|
|
+ {
|
|
|
+ if (bitmap_dpi == dim_conv.GetDstDPI())
|
|
|
+ {
|
|
|
+ // The bitmap was loaded in a different DPI than the base DPI so
|
|
|
+ // we must scale the bitmap properties.
|
|
|
+ expand = expand * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
+ cut = cut * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // The bitmap was loaded in the base DPI and we need to scale it.
|
|
|
+ // Apply the DPI conversion to the skin element scale factor.
|
|
|
+ // FIX: For this to work well, we would need to apply scale to both
|
|
|
+ // image and all the other types of drawing too.
|
|
|
+ // scale_x = scale_x * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
+ // scale_y = scale_y * dim_conv.GetDstDPI() / dim_conv.GetSrcDPI();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this->bitmap_dpi = bitmap_dpi;
|
|
|
}
|
|
|
|
|
|
bool TBSkinElement::HasState(SKIN_STATE state, TBSkinConditionContext &context)
|
|
|
{
|
|
|
- return m_override_elements.GetStateElement(state, context, TBSkinElementState::MATCH_RULE_ONLY_SPECIFIC_STATE) ||
|
|
|
- m_child_elements.GetStateElement(state, context, TBSkinElementState::MATCH_RULE_ONLY_SPECIFIC_STATE) ||
|
|
|
- m_overlay_elements.GetStateElement(state, context, TBSkinElementState::MATCH_RULE_ONLY_SPECIFIC_STATE);
|
|
|
+ return m_override_elements.GetStateElement(state, context, TBSkinElementState::MATCH_RULE_ONLY_SPECIFIC_STATE) ||
|
|
|
+ m_child_elements.GetStateElement(state, context, TBSkinElementState::MATCH_RULE_ONLY_SPECIFIC_STATE) ||
|
|
|
+ m_overlay_elements.GetStateElement(state, context, TBSkinElementState::MATCH_RULE_ONLY_SPECIFIC_STATE);
|
|
|
}
|
|
|
|
|
|
void TBSkinElement::Load(TBNode *n, TBSkin *skin, const char *skin_path)
|
|
|
{
|
|
|
- if (const char *bitmap = n->GetValueString("bitmap", nullptr))
|
|
|
- {
|
|
|
- bitmap_file.Clear();
|
|
|
- bitmap_file.Append(skin_path);
|
|
|
- bitmap_file.Append(bitmap);
|
|
|
- }
|
|
|
-
|
|
|
- // Note: Always read cut and expand as pixels. These values might later be
|
|
|
- // recalculated depending on the DPI the bitmaps are available in.
|
|
|
- cut = n->GetValueInt("cut", cut);
|
|
|
- expand = n->GetValueInt("expand", expand);
|
|
|
-
|
|
|
- name.Set(n->GetName());
|
|
|
- id.Set(n->GetName());
|
|
|
-
|
|
|
- const TBDimensionConverter *dim_conv = skin->GetDimensionConverter();
|
|
|
-
|
|
|
- if (TBNode *padding_node = n->GetNode("padding"))
|
|
|
- {
|
|
|
- TBValue &val = padding_node->GetValue();
|
|
|
- if (val.GetArrayLength() == 4)
|
|
|
- {
|
|
|
- padding_top = dim_conv->GetPxFromValue(val.GetArray()->GetValue(0), 0);
|
|
|
- padding_right = dim_conv->GetPxFromValue(val.GetArray()->GetValue(1), 0);
|
|
|
- padding_bottom = dim_conv->GetPxFromValue(val.GetArray()->GetValue(2), 0);
|
|
|
- padding_left = dim_conv->GetPxFromValue(val.GetArray()->GetValue(3), 0);
|
|
|
- }
|
|
|
- else if (val.GetArrayLength() == 2)
|
|
|
- {
|
|
|
- padding_top = padding_bottom = dim_conv->GetPxFromValue(val.GetArray()->GetValue(0), 0);
|
|
|
- padding_left = padding_right = dim_conv->GetPxFromValue(val.GetArray()->GetValue(1), 0);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- padding_top = padding_right = padding_bottom = padding_left = dim_conv->GetPxFromValue(&val, 0);
|
|
|
- }
|
|
|
- }
|
|
|
- width = skin->GetPxFromNode(n->GetNode("width"), width);
|
|
|
- height = skin->GetPxFromNode(n->GetNode("height"), height);
|
|
|
- pref_width = skin->GetPxFromNode(n->GetNode("pref-width"), pref_width);
|
|
|
- pref_height = skin->GetPxFromNode(n->GetNode("pref-height"), pref_height);
|
|
|
- min_width = skin->GetPxFromNode(n->GetNode("min-width"), min_width);
|
|
|
- min_height = skin->GetPxFromNode(n->GetNode("min-height"), min_height);
|
|
|
- max_width = skin->GetPxFromNode(n->GetNode("max-width"), max_width);
|
|
|
- max_height = skin->GetPxFromNode(n->GetNode("max-height"), max_height);
|
|
|
- spacing = skin->GetPxFromNode(n->GetNode("spacing"), spacing);
|
|
|
- content_ofs_x = skin->GetPxFromNode(n->GetNode("content-ofs-x"), content_ofs_x);
|
|
|
- content_ofs_y = skin->GetPxFromNode(n->GetNode("content-ofs-y"), content_ofs_y);
|
|
|
- img_position_x = n->GetValueInt("img-position-x", img_position_x);
|
|
|
- img_position_y = n->GetValueInt("img-position-y", img_position_y);
|
|
|
- img_ofs_x = skin->GetPxFromNode(n->GetNode("img-ofs-x"), img_ofs_x);
|
|
|
- img_ofs_y = skin->GetPxFromNode(n->GetNode("img-ofs-y"), img_ofs_y);
|
|
|
- flip_x = n->GetValueInt("flip-x", flip_x);
|
|
|
- flip_y = n->GetValueInt("flip-y", flip_y);
|
|
|
- opacity = n->GetValueFloat("opacity", opacity);
|
|
|
-
|
|
|
- if (const char *color = n->GetValueString("text-color", nullptr))
|
|
|
- text_color.SetFromString(color, strlen(color));
|
|
|
-
|
|
|
- if (const char *color = n->GetValueString("background-color", nullptr))
|
|
|
- bg_color.SetFromString(color, strlen(color));
|
|
|
-
|
|
|
- if (const char *type_str = n->GetValueString("type", nullptr))
|
|
|
- type = StringToType(type_str);
|
|
|
-
|
|
|
- // Create all state elements
|
|
|
- m_override_elements.Load(n->GetNode("overrides"));
|
|
|
- m_strong_override_elements.Load(n->GetNode("strong-overrides"));
|
|
|
- m_child_elements.Load(n->GetNode("children"));
|
|
|
- m_overlay_elements.Load(n->GetNode("overlays"));
|
|
|
+ if (const char *bitmap = n->GetValueString("bitmap", nullptr))
|
|
|
+ {
|
|
|
+ bitmap_file.Clear();
|
|
|
+ bitmap_file.Append(skin_path);
|
|
|
+ bitmap_file.Append(bitmap);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Note: Always read cut and expand as pixels. These values might later be
|
|
|
+ // recalculated depending on the DPI the bitmaps are available in.
|
|
|
+ cut = n->GetValueInt("cut", cut);
|
|
|
+ expand = n->GetValueInt("expand", expand);
|
|
|
+
|
|
|
+ name.Set(n->GetName());
|
|
|
+ id.Set(n->GetName());
|
|
|
+
|
|
|
+ const TBDimensionConverter *dim_conv = skin->GetDimensionConverter();
|
|
|
+
|
|
|
+ if (TBNode *padding_node = n->GetNode("padding"))
|
|
|
+ {
|
|
|
+ TBValue &val = padding_node->GetValue();
|
|
|
+ if (val.GetArrayLength() == 4)
|
|
|
+ {
|
|
|
+ padding_top = dim_conv->GetPxFromValue(val.GetArray()->GetValue(0), 0);
|
|
|
+ padding_right = dim_conv->GetPxFromValue(val.GetArray()->GetValue(1), 0);
|
|
|
+ padding_bottom = dim_conv->GetPxFromValue(val.GetArray()->GetValue(2), 0);
|
|
|
+ padding_left = dim_conv->GetPxFromValue(val.GetArray()->GetValue(3), 0);
|
|
|
+ }
|
|
|
+ else if (val.GetArrayLength() == 2)
|
|
|
+ {
|
|
|
+ padding_top = padding_bottom = dim_conv->GetPxFromValue(val.GetArray()->GetValue(0), 0);
|
|
|
+ padding_left = padding_right = dim_conv->GetPxFromValue(val.GetArray()->GetValue(1), 0);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ padding_top = padding_right = padding_bottom = padding_left = dim_conv->GetPxFromValue(&val, 0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ width = skin->GetPxFromNode(n->GetNode("width"), width);
|
|
|
+ height = skin->GetPxFromNode(n->GetNode("height"), height);
|
|
|
+ pref_width = skin->GetPxFromNode(n->GetNode("pref-width"), pref_width);
|
|
|
+ pref_height = skin->GetPxFromNode(n->GetNode("pref-height"), pref_height);
|
|
|
+ min_width = skin->GetPxFromNode(n->GetNode("min-width"), min_width);
|
|
|
+ min_height = skin->GetPxFromNode(n->GetNode("min-height"), min_height);
|
|
|
+ max_width = skin->GetPxFromNode(n->GetNode("max-width"), max_width);
|
|
|
+ max_height = skin->GetPxFromNode(n->GetNode("max-height"), max_height);
|
|
|
+ spacing = skin->GetPxFromNode(n->GetNode("spacing"), spacing);
|
|
|
+ content_ofs_x = skin->GetPxFromNode(n->GetNode("content-ofs-x"), content_ofs_x);
|
|
|
+ content_ofs_y = skin->GetPxFromNode(n->GetNode("content-ofs-y"), content_ofs_y);
|
|
|
+ img_position_x = n->GetValueInt("img-position-x", img_position_x);
|
|
|
+ img_position_y = n->GetValueInt("img-position-y", img_position_y);
|
|
|
+ img_ofs_x = skin->GetPxFromNode(n->GetNode("img-ofs-x"), img_ofs_x);
|
|
|
+ img_ofs_y = skin->GetPxFromNode(n->GetNode("img-ofs-y"), img_ofs_y);
|
|
|
+ flip_x = n->GetValueInt("flip-x", flip_x);
|
|
|
+ flip_y = n->GetValueInt("flip-y", flip_y);
|
|
|
+ opacity = n->GetValueFloat("opacity", opacity);
|
|
|
+
|
|
|
+ if (const char *color = n->GetValueString("text-color", nullptr))
|
|
|
+ text_color.SetFromString(color, strlen(color));
|
|
|
+
|
|
|
+ if (const char *color = n->GetValueString("background-color", nullptr))
|
|
|
+ bg_color.SetFromString(color, strlen(color));
|
|
|
+
|
|
|
+ if (const char *type_str = n->GetValueString("type", nullptr))
|
|
|
+ type = StringToType(type_str);
|
|
|
+
|
|
|
+ // Create all state elements
|
|
|
+ m_override_elements.Load(n->GetNode("overrides"));
|
|
|
+ m_strong_override_elements.Load(n->GetNode("strong-overrides"));
|
|
|
+ m_child_elements.Load(n->GetNode("children"));
|
|
|
+ m_overlay_elements.Load(n->GetNode("overlays"));
|
|
|
}
|
|
|
|
|
|
// == TBSkinElementState ====================================================
|
|
|
|
|
|
bool TBSkinElementState::IsMatch(SKIN_STATE state, TBSkinConditionContext &context, MATCH_RULE rule) const
|
|
|
{
|
|
|
- if (rule == MATCH_RULE_ONLY_SPECIFIC_STATE && this->state == SKIN_STATE_ALL)
|
|
|
- return false;
|
|
|
- if ((state & this->state) || this->state == SKIN_STATE_ALL)
|
|
|
- {
|
|
|
- for (TBSkinCondition *condition = conditions.GetFirst(); condition; condition = condition->GetNext())
|
|
|
- if (!condition->GetCondition(context))
|
|
|
- return false;
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
+ if (rule == MATCH_RULE_ONLY_SPECIFIC_STATE && this->state == SKIN_STATE_ALL)
|
|
|
+ return false;
|
|
|
+ if ((state & this->state) || this->state == SKIN_STATE_ALL)
|
|
|
+ {
|
|
|
+ for (TBSkinCondition *condition = conditions.GetFirst(); condition; condition = condition->GetNext())
|
|
|
+ if (!condition->GetCondition(context))
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
bool TBSkinElementState::IsExactMatch(SKIN_STATE state, TBSkinConditionContext &context, MATCH_RULE rule) const
|
|
|
{
|
|
|
- if (rule == MATCH_RULE_ONLY_SPECIFIC_STATE && this->state == SKIN_STATE_ALL)
|
|
|
- return false;
|
|
|
- if (state == this->state || this->state == SKIN_STATE_ALL)
|
|
|
- {
|
|
|
- for (TBSkinCondition *condition = conditions.GetFirst(); condition; condition = condition->GetNext())
|
|
|
- if (!condition->GetCondition(context))
|
|
|
- return false;
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
+ if (rule == MATCH_RULE_ONLY_SPECIFIC_STATE && this->state == SKIN_STATE_ALL)
|
|
|
+ return false;
|
|
|
+ if (state == this->state || this->state == SKIN_STATE_ALL)
|
|
|
+ {
|
|
|
+ for (TBSkinCondition *condition = conditions.GetFirst(); condition; condition = condition->GetNext())
|
|
|
+ if (!condition->GetCondition(context))
|
|
|
+ return false;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
// == TBSkinElementStateList ==================================================
|
|
|
|
|
|
TBSkinElementStateList::~TBSkinElementStateList()
|
|
|
{
|
|
|
- while (TBSkinElementState *state = m_state_elements.GetFirst())
|
|
|
- {
|
|
|
- m_state_elements.Remove(state);
|
|
|
- delete state;
|
|
|
- }
|
|
|
+ while (TBSkinElementState *state = m_state_elements.GetFirst())
|
|
|
+ {
|
|
|
+ m_state_elements.Remove(state);
|
|
|
+ delete state;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
TBSkinElementState *TBSkinElementStateList::GetStateElement(SKIN_STATE state, TBSkinConditionContext &context, TBSkinElementState::MATCH_RULE rule) const
|
|
|
{
|
|
|
- // First try to get a state element with a exact match to the current state
|
|
|
- if (TBSkinElementState *element_state = GetStateElementExactMatch(state, context, rule))
|
|
|
- return element_state;
|
|
|
- // No exact state match. Get a state with a partly match if there is one.
|
|
|
- TBSkinElementState *state_element = m_state_elements.GetFirst();
|
|
|
- while (state_element)
|
|
|
- {
|
|
|
- if (state_element->IsMatch(state, context, rule))
|
|
|
- return state_element;
|
|
|
- state_element = state_element->GetNext();
|
|
|
- }
|
|
|
- return nullptr;
|
|
|
+ // First try to get a state element with a exact match to the current state
|
|
|
+ if (TBSkinElementState *element_state = GetStateElementExactMatch(state, context, rule))
|
|
|
+ return element_state;
|
|
|
+ // No exact state match. Get a state with a partly match if there is one.
|
|
|
+ TBSkinElementState *state_element = m_state_elements.GetFirst();
|
|
|
+ while (state_element)
|
|
|
+ {
|
|
|
+ if (state_element->IsMatch(state, context, rule))
|
|
|
+ return state_element;
|
|
|
+ state_element = state_element->GetNext();
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
TBSkinElementState *TBSkinElementStateList::GetStateElementExactMatch(SKIN_STATE state, TBSkinConditionContext &context, TBSkinElementState::MATCH_RULE rule) const
|
|
|
{
|
|
|
- TBSkinElementState *state_element = m_state_elements.GetFirst();
|
|
|
- while (state_element)
|
|
|
- {
|
|
|
- if (state_element->IsExactMatch(state, context, rule))
|
|
|
- return state_element;
|
|
|
- state_element = state_element->GetNext();
|
|
|
- }
|
|
|
- return nullptr;
|
|
|
+ TBSkinElementState *state_element = m_state_elements.GetFirst();
|
|
|
+ while (state_element)
|
|
|
+ {
|
|
|
+ if (state_element->IsExactMatch(state, context, rule))
|
|
|
+ return state_element;
|
|
|
+ state_element = state_element->GetNext();
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
|
|
|
void TBSkinElementStateList::Load(TBNode *n)
|
|
|
{
|
|
|
- if (!n)
|
|
|
- return;
|
|
|
-
|
|
|
- // For each node, create a new state element.
|
|
|
- TBNode *element_node = n->GetFirstChild();
|
|
|
- while (element_node)
|
|
|
- {
|
|
|
- TBSkinElementState *state = new TBSkinElementState;
|
|
|
- if (!state)
|
|
|
- return;
|
|
|
-
|
|
|
- // By default, a state element applies to all combinations of states
|
|
|
- state->state = SKIN_STATE_ALL;
|
|
|
- state->element_id.Set(element_node->GetValue().GetString());
|
|
|
-
|
|
|
- // Loop through all nodes, read state and create all found conditions.
|
|
|
- for (TBNode *condition_node = element_node->GetFirstChild(); condition_node; condition_node = condition_node->GetNext())
|
|
|
- {
|
|
|
- if (strcmp(condition_node->GetName(), "state") == 0)
|
|
|
- state->state = StringToState(condition_node->GetValue().GetString());
|
|
|
- else if (strcmp(condition_node->GetName(), "condition") == 0)
|
|
|
- {
|
|
|
- TBSkinCondition::TARGET target = StringToTarget(condition_node->GetValueString("target", ""));
|
|
|
-
|
|
|
- const char *prop_str = condition_node->GetValueString("property", "");
|
|
|
- TBSkinCondition::PROPERTY prop = StringToProperty(prop_str);
|
|
|
- TBID custom_prop;
|
|
|
- if (prop == TBSkinCondition::PROPERTY_CUSTOM)
|
|
|
- custom_prop.Set(prop_str);
|
|
|
-
|
|
|
- TBID value;
|
|
|
- if (TBNode *value_n = condition_node->GetNode("value"))
|
|
|
- {
|
|
|
- // Set the it to number or string. If it's a state, we must first convert the
|
|
|
- // state string to the SKIN_STATE state combo.
|
|
|
- if (prop == TBSkinCondition::PROPERTY_STATE)
|
|
|
- value.Set(StringToState(value_n->GetValue().GetString()));
|
|
|
- else if (value_n->GetValue().IsString())
|
|
|
- value.Set(value_n->GetValue().GetString());
|
|
|
- else
|
|
|
- value.Set(value_n->GetValue().GetInt());
|
|
|
- }
|
|
|
-
|
|
|
- TBSkinCondition::TEST test = TBSkinCondition::TEST_EQUAL;
|
|
|
- if (const char *test_str = condition_node->GetValueString("test", nullptr))
|
|
|
- {
|
|
|
- if (strcmp(test_str, "!=") == 0)
|
|
|
- test = TBSkinCondition::TEST_NOT_EQUAL;
|
|
|
- }
|
|
|
-
|
|
|
- if (TBSkinCondition *condition = new TBSkinCondition(target, prop, custom_prop, value, test))
|
|
|
- state->conditions.AddLast(condition);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // State is reado to add
|
|
|
- m_state_elements.AddLast(state);
|
|
|
- element_node = element_node->GetNext();
|
|
|
- }
|
|
|
+ if (!n)
|
|
|
+ return;
|
|
|
+
|
|
|
+ // For each node, create a new state element.
|
|
|
+ TBNode *element_node = n->GetFirstChild();
|
|
|
+ while (element_node)
|
|
|
+ {
|
|
|
+ TBSkinElementState *state = new TBSkinElementState;
|
|
|
+ if (!state)
|
|
|
+ return;
|
|
|
+
|
|
|
+ // By default, a state element applies to all combinations of states
|
|
|
+ state->state = SKIN_STATE_ALL;
|
|
|
+ state->element_id.Set(element_node->GetValue().GetString());
|
|
|
+
|
|
|
+ // Loop through all nodes, read state and create all found conditions.
|
|
|
+ for (TBNode *condition_node = element_node->GetFirstChild(); condition_node; condition_node = condition_node->GetNext())
|
|
|
+ {
|
|
|
+ if (strcmp(condition_node->GetName(), "state") == 0)
|
|
|
+ state->state = StringToState(condition_node->GetValue().GetString());
|
|
|
+ else if (strcmp(condition_node->GetName(), "condition") == 0)
|
|
|
+ {
|
|
|
+ TBSkinCondition::TARGET target = StringToTarget(condition_node->GetValueString("target", ""));
|
|
|
+
|
|
|
+ const char *prop_str = condition_node->GetValueString("property", "");
|
|
|
+ TBSkinCondition::PROPERTY prop = StringToProperty(prop_str);
|
|
|
+ TBID custom_prop;
|
|
|
+ if (prop == TBSkinCondition::PROPERTY_CUSTOM)
|
|
|
+ custom_prop.Set(prop_str);
|
|
|
+
|
|
|
+ TBID value;
|
|
|
+ if (TBNode *value_n = condition_node->GetNode("value"))
|
|
|
+ {
|
|
|
+ // Set the it to number or string. If it's a state, we must first convert the
|
|
|
+ // state string to the SKIN_STATE state combo.
|
|
|
+ if (prop == TBSkinCondition::PROPERTY_STATE)
|
|
|
+ value.Set(StringToState(value_n->GetValue().GetString()));
|
|
|
+ else if (value_n->GetValue().IsString())
|
|
|
+ value.Set(value_n->GetValue().GetString());
|
|
|
+ else
|
|
|
+ value.Set(value_n->GetValue().GetInt());
|
|
|
+ }
|
|
|
+
|
|
|
+ TBSkinCondition::TEST test = TBSkinCondition::TEST_EQUAL;
|
|
|
+ if (const char *test_str = condition_node->GetValueString("test", nullptr))
|
|
|
+ {
|
|
|
+ if (strcmp(test_str, "!=") == 0)
|
|
|
+ test = TBSkinCondition::TEST_NOT_EQUAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (TBSkinCondition *condition = new TBSkinCondition(target, prop, custom_prop, value, test))
|
|
|
+ state->conditions.AddLast(condition);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // State is reado to add
|
|
|
+ m_state_elements.AddLast(state);
|
|
|
+ element_node = element_node->GetNext();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
}; // namespace tb
|