void HKWidgetRenderer::Render(const HKWidget &widget, const MFMatrix &worldTransform) { MFVector widgetColour = widget.GetColour(); MFVector size = widget.GetSize(); size.x -= padding.x + padding.z; size.y -= padding.y + padding.w; if(colour.w > 0.f) { float borderWidth = border.x + border.z; float borderHeight = border.y + border.w; MFPrimitive_DrawUntexturedQuad(padding.x + border.x, padding.y + border.y, size.x - borderWidth, size.y - borderHeight, colour*widgetColour, worldTransform); } if(border.x > 0.f) // left MFPrimitive_DrawUntexturedQuad(padding.x, padding.y, border.x, size.y, borderColour*widgetColour, worldTransform); if(border.y > 0.f) // top MFPrimitive_DrawUntexturedQuad(padding.x, padding.y, size.x, border.y, borderColour*widgetColour, worldTransform); if(border.z > 0.f) // right MFPrimitive_DrawUntexturedQuad(size.x - border.z + padding.x, padding.y, border.z, size.y, borderColour*widgetColour, worldTransform); if(border.w > 0.f) // bottom MFPrimitive_DrawUntexturedQuad(padding.x, padding.y + size.y - border.w, size.x, border.w, borderColour*widgetColour, worldTransform); if(pImage) { if(margin9Cell > 0.f) { // 9 cell stuff... } else { // draw the background image centered in the box MFMaterial_SetMaterial(pImage); float offset = 0; float tc = MFRenderer_GetTexelCenterOffset(); if(tc > 0.f) { if(size.x == texWidth && size.y == texHeight) offset = tc; } MFPrimitive_DrawQuad(padding.x - offset, padding.y - offset, size.x, size.y, widgetColour, 0, 0, 1, 1, worldTransform); } } }
HKWidget *HKUserInterface::CreateWidget(const char *pWidgetType) { HKWidgetFactory::FactoryType *pType; HKWidget *pWidget = pFactory->Create(pWidgetType, &pType); if(!pWidget) return NULL; HKWidgetRenderer *pRenderer = pRendererFactory->Create(pWidgetType); while(!pRenderer && pType->pParent) { pType = pType->pParent; pRenderer = pRendererFactory->Create(pType->typeName); } if(pRenderer) pWidget->SetRenderer(pRenderer); return pWidget; }
void HKWidgetRendererLabel::Render(const HKWidget &widget, const MFMatrix &worldTransform) { HKWidgetRenderer::Render(widget, worldTransform); HKWidgetLabel &label = (HKWidgetLabel&)widget; MFString l = label.GetText(); if(!l.IsEmpty()) { MFFont *pFont = label.GetFont(); float height = label.GetTextHeight(); float shadowDepth = label.GetShadowDepth(); const MFVector &size = widget.GetSize(); const MFVector &colour = widget.GetColour(); const MFVector &textColour = label.GetTextColour(); MFFontJustify j = label.GetTextJustification(); const char *pString = l.CStr(); if(shadowDepth > 0.f) MFFont_DrawTextJustified(pFont, pString, MakeVector(shadowDepth, shadowDepth), size.x, size.y, j, height, MFVector::black, -1, worldTransform); MFFont_DrawTextJustified(pFont, pString, MFVector::zero, size.x, size.y, j, height, textColour * colour, -1, worldTransform); } }
void HKWidgetListbox::ArrangeChildren() { // early out? int numChildren = GetNumChildren(); if(numChildren == 0) return; MFVector pPos = orientation == Horizontal ? MakeVector(padding.x + scrollOffset, padding.y) : MakeVector(padding.x, padding.y + scrollOffset); MFVector pSize = MakeVector(size.x - (padding.x + padding.z), size.y - (padding.y + padding.w)); contentSize = 0.f; for(int a=0; a<numChildren; ++a) { HKWidget *pWidget = GetChild(a); if(pWidget->GetVisible() == Gone) continue; const MFVector &cMargin = pWidget->GetLayoutMargin(); const MFVector &cSize = pWidget->GetSize(); MFVector tPos = pPos + MakeVector(cMargin.x, cMargin.y); MFVector tSize = MFMax(pSize - MakeVector(cMargin.x + cMargin.z, cMargin.y + cMargin.w), MFVector::zero); if(orientation == Horizontal) { float itemSize = cSize.x + cMargin.x + cMargin.z; contentSize += itemSize; pPos.x += itemSize; pWidget->SetPosition(tPos); pWidget->SetHeight(tSize.y); } else { float itemSize = cSize.y + cMargin.y + cMargin.w; contentSize += itemSize; pPos.y += itemSize; pWidget->SetPosition(tPos); pWidget->SetWidth(tSize.x); } } }
void HKWidgetLayoutLinear::ArrangeChildren() { bool bFitWidth = bAutoWidth && GetHAlign() != Align_Fill; // fitFlags & FitContentHorizontal bool bFitHeight = bAutoHeight && GetVAlign() != VAlign_Fill; // fitFlags & FitContentVertical // early out? int numChildren = GetNumChildren(); if(numChildren == 0) { if(bFitWidth || bFitHeight) { // resize the layout MFVector newSize = GetSize(); if(bFitWidth) newSize.x = padding.x + padding.z; if(bFitHeight) newSize.y = padding.y + padding.w; Resize(newSize); } return; } // calculate weight and fit float totalWeight = 0.f; MFVector fit = MakeVector(padding.x + padding.z, padding.y + padding.w); for(int a=0; a<numChildren; ++a) { HKWidget *pWidget = GetChild(a); if(pWidget->GetVisible() == Gone) continue; const MFVector &cSize = pWidget->GetSizeWithMargin(); if(orientation == Horizontal) { if(pWidget->GetHAlign() == Align_Fill) // fill horizontally totalWeight += pWidget->GetLayoutWeight(); else fit.x += cSize.x; fit.y = MFMax(fit.y, cSize.y + padding.y + padding.w); } else { if(pWidget->GetVAlign() == VAlign_Fill) // fill vertically totalWeight += pWidget->GetLayoutWeight(); else fit.y += cSize.y; fit.x = MFMax(fit.x, cSize.x + padding.x + padding.z); } } if(bFitWidth || bFitHeight) { // resize the layout MFVector newSize = size; if(bFitWidth) newSize.x = fit.x; if(bFitHeight) newSize.y = fit.y; Resize(newSize); } MFVector pPos = MakeVector(padding.x, padding.y); MFVector pSize = MakeVector(size.x - (padding.x + padding.z), size.y - (padding.y + padding.w)); MFVector slack = MFMax(size - fit, MFVector::zero); for(int a=0; a<numChildren; ++a) { HKWidget *pWidget = GetChild(a); if(pWidget->GetVisible() == Gone) continue; const MFVector &cMargin = pWidget->GetLayoutMargin(); const MFVector &cSize = pWidget->GetSize(); MFVector tPos = pPos + MakeVector(cMargin.x, cMargin.y); MFVector tSize = MFMax(pSize - MakeVector(cMargin.x + cMargin.z, cMargin.y + cMargin.w), MFVector::zero); Align align = pWidget->GetHAlign(); VAlign valign = pWidget->GetVAlign(); MFVector newSize = cSize; if(orientation == Horizontal) { if(align == Align_Fill) // fill horizontally { // this widget fills available empty space in the parent container newSize.x = slack.x * (pWidget->GetLayoutWeight() / totalWeight); pPos.x += newSize.x; newSize.x = MFMax(0.f, newSize.x - cMargin.x - cMargin.z); } else { pPos.x += cSize.x + cMargin.x + cMargin.z; } switch(valign) { case VAlign_None: case VAlign_Top: pWidget->SetPosition(tPos); break; case VAlign_Center: pWidget->SetPosition(tPos + MakeVector(0, MFMax(tSize.y - cSize.y, 0.f) * 0.5f)); break; case VAlign_Bottom: pWidget->SetPosition(tPos + MakeVector(0, MFMax(tSize.y - cSize.y, 0.f))); break; case VAlign_Fill: pWidget->SetPosition(tPos); newSize.y = tSize.y; break; default: MFUNREACHABLE; } } else { if(valign == VAlign_Fill) // fill vertically { // this widget fills available empty space in the parent container newSize.y = slack.y * (pWidget->GetLayoutWeight() / totalWeight); pPos.y += newSize.y; newSize.y = MFMax(0.f, newSize.y - cMargin.y - cMargin.w); } else { pPos.y += cSize.y + cMargin.y + cMargin.w; } switch(align) { case Align_None: case Align_Left: pWidget->SetPosition(tPos); break; case Align_Center: pWidget->SetPosition(tPos + MakeVector(MFMax(tSize.x - cSize.x, 0.f) * 0.5f, 0)); break; case Align_Right: pWidget->SetPosition(tPos + MakeVector(MFMax(tSize.x - cSize.x, 0.f), 0)); break; case Align_Fill: pWidget->SetPosition(tPos); newSize.x = tSize.x; break; default: MFUNREACHABLE; } } ResizeChild(pWidget, newSize); } }
void HKWidgetLayoutFrame::ArrangeChildren() { bool bFitWidth = bAutoWidth && GetHAlign() != Align_Fill; // fitFlags & FitContentHorizontal bool bFitHeight = bAutoHeight && GetVAlign() != VAlign_Fill; // fitFlags & FitContentVertical // early out? int numChildren = GetNumChildren(); if(numChildren == 0) { if(bFitWidth || bFitHeight) { // resize the layout MFVector newSize = GetSize(); if(bFitWidth) newSize.x = padding.x + padding.z; if(bFitHeight) newSize.y = padding.y + padding.w; Resize(newSize); } return; } if(bFitWidth || bFitHeight) { // fit to largest child in each dimension MFVector fit = MFVector::zero; for(int a=0; a<numChildren; ++a) { HKWidget *pWidget = GetChild(a); const MFVector &cSize = pWidget->GetSizeWithMargin(); fit.x = MFMax(fit.x, cSize.x + padding.x + padding.z); fit.y = MFMax(fit.y, cSize.y + padding.y + padding.w); } // resize the layout MFVector newSize = GetSize(); if(bFitWidth) newSize.x = fit.x; if(bFitHeight) newSize.y = fit.y; Resize(newSize); } MFVector cPos = MakeVector(padding.x, padding.y); MFVector cSize = MakeVector(size.x - (padding.x + padding.z), size.y - (padding.y + padding.w)); for(int a=0; a<numChildren; ++a) { HKWidget *pWidget = GetChild(a); const MFVector &cMargin = pWidget->GetLayoutMargin(); const MFVector &size = pWidget->GetSize(); MFVector tPos = cPos + MakeVector(cMargin.x, cMargin.y); MFVector tSize = cSize - MakeVector(cMargin.x + cMargin.z, cMargin.y + cMargin.w); switch(pWidget->GetLayoutJustification()) { case TopLeft: pWidget->SetPosition(tPos); break; case TopCenter: pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, 0)); break; case TopRight: pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, 0)); break; case TopFill: pWidget->SetPosition(tPos); ResizeChild(pWidget, MakeVector(tSize.x, size.y)); break; case CenterLeft: pWidget->SetPosition(tPos + MakeVector(0, (tSize.y - size.y) * 0.5f)); break; case Center: pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, (tSize.y - size.y) * 0.5f)); break; case CenterRight: pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, (tSize.y - size.y) * 0.5f)); break; case CenterFill: pWidget->SetPosition(tPos + MakeVector(0, (tSize.y - size.y) * 0.5f)); ResizeChild(pWidget, MakeVector(tSize.x, size.y)); break; case BottomLeft: pWidget->SetPosition(tPos + MakeVector(0, tSize.y - size.y)); break; case BottomCenter: pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, tSize.y - size.y)); break; case BottomRight: pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, tSize.y - size.y)); break; case BottomFill: pWidget->SetPosition(tPos + MakeVector(0, tSize.y - size.y)); ResizeChild(pWidget, MakeVector(tSize.x, size.y)); break; case FillLeft: pWidget->SetPosition(tPos); ResizeChild(pWidget, MakeVector(size.x, tSize.y)); break; case FillCenter: pWidget->SetPosition(tPos + MakeVector((tSize.x - size.x) * 0.5f, 0)); ResizeChild(pWidget, MakeVector(size.x, tSize.y)); break; case FillRight: pWidget->SetPosition(tPos + MakeVector(tSize.x - size.x, 0)); ResizeChild(pWidget, MakeVector(size.x, tSize.y)); break; case Fill: pWidget->SetPosition(tPos); ResizeChild(pWidget, tSize); break; case None: // this widget has absolute coordinates.. default: break; } } }
void HKUserInterface::OnInputEvent(HKInputManager &manager, const HKInputManager::EventInfo &ev) { HKWidget *pFocusWidget = pFocusList[ev.pSource->sourceID]; if(ev.pSource->device == IDD_Mouse || ev.pSource->device == IDD_TouchPanel) { // positional events will be sent to the hierarchy MFVector pos = { ev.hover.x, ev.hover.y, 0.f, 1.f }; MFVector dir = { 0.f, 0.f, 1.f, 1.f }; MFVector localPos; HKWidget *pWidget = NULL; if(pFocusWidget) { pWidget = pFocusWidget->IntersectWidget(pos, dir, &localPos); if(!pWidget) pWidget = pFocusWidget; } else { pWidget = pRoot->IntersectWidget(pos, dir, &localPos); } // update the down widget if(ev.ev == HKInputManager::IE_Down) pDownOver[ev.pSource->sourceID] = pWidget; else if(ev.ev == HKInputManager::IE_Tap) { // if we receive a tap event, check that it was on the same widget we recorded the down event for if(pDownOver[ev.pSource->sourceID] != pWidget) return; } // check if the hover has changed HKWidget *pHover = pHoverList[ev.pSource->sourceID]; if(pHover != pWidget) { pHoverList[ev.pSource->sourceID] = pWidget; if(pHover) { HKWidgetInputEvent ie(pHover, ev.pSource); pHover->OnHoverOut(*pHover, ie); } if(pWidget) { HKWidgetInputEvent ie(pWidget, ev.pSource); pWidget->OnHoverOver(*pWidget, ie); } } if(pWidget) { HKInputManager::EventInfo transformedEv = ev; LocaliseInput(transformedEv, pWidget, localPos); // send the input event if(pWidget->InputEvent(manager, transformedEv)) return; } } else if(pFocusWidget) { // non-positional events pFocusWidget->InputEvent(manager, ev); } }