#include "pch.h" #include "log.h" #include "node_scroll.h" #include "renderer_gl/opengl_capabilities.h" #include "event.h" #include "shader.h" Node* NodeScroll::clone_instantiate() const { return new NodeScroll; } void NodeScroll::fix_scroll() { auto pad = GetPadding(); glm::vec2 padoff = { pad[1] + pad[3], pad[0] + pad[2] }; auto rect = get_children_rect(); if (rect.w > 0 && rect.z > 0) { m_offset = glm::clamp(m_offset, -zw(rect) + zw(m_clip_uncut) - padoff, { 0, 0 }); m_pos_offset_childred = m_offset; } else { m_pos_offset_childred = m_offset = { 0, 0 }; } } void NodeScroll::clone_copy(Node* dest) const { NodeBorder::clone_copy(dest); auto n = static_cast(dest); n->m_scrollbar_color = m_scrollbar_color; n->m_mask = m_mask; n->m_direction = m_direction; } void NodeScroll::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { NodeBorder::parse_attributes(ka, attr); switch (ka) { case kAttribute::ScrollColor: { glm::vec4 col; int n = sscanf(attr->Value(), "%f %f %f %f", &col.x, &col.y, &col.z, &col.w); if (n == 1) m_scrollbar_color = glm::vec4(col.x, col.x, col.x, 1); else m_scrollbar_color = col; break; } case kAttribute::ScrollDir: if (strcmp(attr->Value(), "vertical") == 0 || strcmp(attr->Value(), "v") == 0) { m_direction = kScrollDirection::Vertical; m_mask = { 0, 1 }; } else if (strcmp(attr->Value(), "horizontal") == 0 || strcmp(attr->Value(), "h") == 0) { m_direction = kScrollDirection::Horizontal; m_mask = { 1, 0 }; } break; default: break; } } void NodeScroll::on_tick(float dt) { auto pad = GetPadding(); auto rect = get_children_rect(); if (rect.w > 0 && rect.z > 0) { // fix scrollbar if (m_direction == kScrollDirection::Vertical) { float szv = m_size.y - (pad[0] + pad[2]); float new_padv = rect.w == 0 || rect.w <= szv + 2 ? 5 : 35; if (pad[1] != new_padv) { YGNodeStyleSetPadding(y_node, YGEdgeRight, new_padv); app_redraw(); } } else { float szh = m_size.x - (pad[3] + pad[1]); float new_padh = rect.z == 0 || rect.z <= szh + 2 ? 5 : 35; if (pad[2] != new_padh) { YGNodeStyleSetPadding(y_node, YGEdgeBottom, new_padh); app_redraw(); } } } else { SetPadding(0, 0, 0, 0); } } void NodeScroll::draw() { NodeBorder::draw(); fix_scroll(); glm::vec4 rect = get_children_rect(); glm::vec4 pad = GetPadding(); if (rect.w > 0 && rect.z > 0) { glDisable(pp::renderer::gl::blend_state()); ShaderManager::use(kShader::Color); if (m_direction == kScrollDirection::Vertical) { float sz = m_size.y - (pad[0] + pad[2]); float h = glm::max(30.f, sz / rect.w * sz); float offset_percent = m_offset.y / (rect.w - sz); float pr = YGNodeLayoutGetPadding(y_node, YGEdgeRight) - 5; ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * glm::translate(glm::vec3(m_pos.x + m_size.x - pr, m_pos.y - offset_percent * (sz - h) + pad[0], 0)) * glm::scale(glm::vec3(pr, h, 1)) * glm::translate(glm::vec3(.5, .5, 0)) ); } else { float sz = m_size.x - (pad[3] + pad[1]); float h = glm::max(30.f, sz / rect.z * sz); float offset_percent = m_offset.x / (rect.z - sz); float pr = YGNodeLayoutGetPadding(y_node, YGEdgeBottom) - 5; ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * glm::translate(glm::vec3(m_pos.x - offset_percent * (sz - h) + pad[3], m_pos.y + m_size.y - pr, 0)) * glm::scale(glm::vec3(h, pr, 1)) * glm::translate(glm::vec3(.5, .5, 0)) ); } ShaderManager::u_vec4(kShaderUniform::Col, m_scrollbar_color); m_plane.draw_fill(); } } kEventResult NodeScroll::handle_event(Event* e) { NodeBorder::handle_event(e); auto me = static_cast(e); auto ge = static_cast(e); //auto loc = (me->m_pos - m_pos) * root()->m_zoom; switch (e->m_type) { case kEventType::MouseDownL: m_dragging = true; m_drag_start = me->m_pos; m_offset_start = m_offset; // if click on the scroll area use scrolling direction, otherwise natural if (m_direction == kScrollDirection::Vertical) m_drag_dir = (me->m_pos.x - m_pos.x) > (m_size.x - YGNodeLayoutGetPadding(y_node, YGEdgeRight)) ? -1 : 1; else m_drag_dir = (me->m_pos.y - m_pos.y) > (m_size.y - YGNodeLayoutGetPadding(y_node, YGEdgeBottom)) ? -1 : 1; mouse_capture(); break; case kEventType::MouseMove: if (m_dragging) { glm::vec4 rect = get_children_rect(); glm::vec4 pad = GetPadding(); if (rect.w > 0 && rect.z > 0) { if (m_direction == kScrollDirection::Vertical) { float speed = m_drag_dir < 0 ? rect.w / (m_size.y - (pad[0] + pad[2])) : 1; m_offset = m_offset_start + (me->m_pos - m_drag_start) * m_mask * m_drag_dir * speed; } else { float speed = m_drag_dir < 0 ? rect.z / (m_size.x - (pad[3] + pad[1])) : 1; m_offset = m_offset_start + (me->m_pos - m_drag_start) * m_mask * m_drag_dir * speed; } fix_scroll(); } } break; case kEventType::MouseUpL: mouse_release(); m_dragging = false; break; case kEventType::MouseScroll: m_offset += me->m_scroll_delta * 50 * m_mask; fix_scroll(); break; case kEventType::GestureStart: m_offset_start = m_offset; mouse_capture(); break; case kEventType::GestureMove: m_offset = m_offset_start + ge->m_pos_delta * m_mask; fix_scroll(); break; case kEventType::GestureEnd: mouse_release(); break; case kEventType::MouseCancel: mouse_release(); m_dragging = false; break; default: return kEventResult::Available; break; } return kEventResult::Consumed; }