#include "UIMLView.h" #include "XML.h" #include "TextFeld.h" #include "Knopf.h" #include "Tabelle.h" #include "Fenster.h" #include "Schrift.h" #include "Bildschirm.h" #include "Rahmen.h" #include "Scroll.h" #include "Bild.h" using namespace Framework; // Erstellt eine UIML View UIMLView::UIMLView() : ZeichnungHintergrund() { style = Style::MEIgnoreInside | Style::MEIgnoreParentInside | Style::MEIgnoreSichtbar | Style::MEIgnoreVerarbeitet; members = new Trie< Zeichnung >(); dom = 0; nextId = 0; memset(&init, 0, sizeof(UIInit)); } // Erstellt eine UIML View zu einem UIML Text // uiml: Ein xml element gemät des ksg uiml standarts UIMLView::UIMLView(XML::Element* uiml, UIInit& init) : ZeichnungHintergrund() { this->init = init; members = new Trie< Zeichnung >(); dom = 0; nextId = 0; setUIML(uiml); } // Erstellt eine UIML View zu einem UIML Text // uiml: Ein xml text gemät des ksg uiml standarts UIMLView::UIMLView(Text uiml, UIInit& init) { this->init = init; members = new Trie< Zeichnung >(); dom = 0; setUIML(uiml); } UIMLView::~UIMLView() { if (dom) dom->release(); members->release(); } // Verarbeitet ein Maus Ereignis. Wird vom Framework automatisch aufgerufen. // me: Das Ereignis void UIMLView::doMausEreignis(MausEreignis& me, bool userRet) { if (dom) { bool verarbeitet = me.verarbeitet; me.verarbeitet |= hatStyleNicht(Style::Sichtbar); bool insideParent = me.insideParent; if (!hatStyle(Style::Sichtbar) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet) me.insideParent = 0; int rbr = 0; if (hatStyle(Style::Rahmen) && rahmen) rbr = rahmen->getRBreite(); me.mx -= rbr; me.my -= rbr; if (hatStyle(Style::VScroll) && vertikalScrollBar) me.my += vertikalScrollBar->getScroll(); if (hatStyle(Style::HScroll) && horizontalScrollBar) me.mx += horizontalScrollBar->getScroll(); if (dom) { for (auto i = dom->getChilds(); i; i++) { // TODO render elements backwards Zeichnung* z = members->z(i->getAttributeValue("id"), i->getAttributeValue("id").getLength()); if (z) z->doPublicMausEreignis(me); } } me.mx += rbr; me.my += rbr; if (hatStyle(Style::VScroll) && vertikalScrollBar) me.my -= vertikalScrollBar->getScroll(); if (hatStyle(Style::HScroll) && horizontalScrollBar) me.mx -= horizontalScrollBar->getScroll(); if (!hatStyle(Style::Sichtbar) || !me.insideParent || me.verarbeitet || me.mx < 0 || me.my < 0 || me.mx >= gr.x || me.my >= gr.y || !userRet) me.insideParent = insideParent; else me.verarbeitet = 1; if (hatStyleNicht(Style::Sichtbar)) me.verarbeitet = verarbeitet; } } void UIMLView::parseTable(Iterator childs, ObjTabelle* table) { for (auto i = childs; i; i++) { Text id; if (i->hasAttribute("id")) id = i->getAttributeValue("id"); else { id = Text("_") += nextId++; i->setAttribute("id", id); } if (i->getName().istGleich("tr")) { table->addZeile(id); Text line = id; int c = 1; for (auto j = i->getChilds(); j; j++) { Zeichnung* z = parseElement(j._); if (table->getSpaltenAnzahl() < c) table->addSpalte(Text(c - 1)); if (z) table->setZeichnungZ((char*)Text(c - 1), (char*)line, dynamic_cast(z->getThis())); c++; } } } } void UIMLView::parseFrame(Iterator childs, Fenster* frame) { for (auto i = childs; i; i++) { Zeichnung* z = parseElement(i._); if (z) frame->addMember(dynamic_cast(z->getThis())); } } Zeichnung* UIMLView::parseElement(XML::Element* e) { Text id; if (e->hasAttribute("id")) id = e->getAttributeValue("id"); else { id = Text("_") += nextId++; e->setAttribute("id", id); } Zeichnung* z = members->z(id, id.getLength()); if (!z) { // precompute attributes if (e->hasAttribute("margin")) { Text m = e->getAttributeValue("margin"); if (!e->hasAttribute("margin-left")) e->setAttribute("margin-left", m); if (!e->hasAttribute("margin-top")) e->setAttribute("margin-top", m); if (!e->hasAttribute("margin-right")) e->setAttribute("margin-right", m); if (!e->hasAttribute("margin-bottom")) e->setAttribute("margin-bottom", m); } if (e->hasAttribute("class")) { Text c = e->getAttributeValue("class"); while (1) { Text* t; if (c.hat(",")) t = c.getTeilText(0, c.positionVon(',')); else t = new Text(c); XML::Editor ce = dom->selectChildsByName("class").whereAttributeEquals("id", *t); for (auto i = ce.begin(); i; i++) { for (auto j = i->getAttributeNames(), k = i->getAttributeValues(); j && k; j++, k++) { if (!e->hasAttribute(j->getText())) e->setAttribute(j->getText(), i->getText()); } } t->release(); if (c.hat(",")) c.remove(0, c.positionVon(',' + 1)); else break; } } if (e->hasAttribute("text-align")) { if (!e->hasAttribute("text-align-horizontal")) e->setAttribute("text-align-horizontal", e->getAttributeValue("text-align")); if (!e->hasAttribute("text-align-vertical")) e->setAttribute("text-align-vertical", e->getAttributeValue("text-align")); } // create objects if (e->getName().istGleich("textfield") || e->getName().istGleich("text") || e->getName().istGleich("textarea")) { TextFeld* t = init.createTextFeld(init.initParam); if (e->getName().istGleich("textfield")) t->addStyle(TextFeld::Style::TextFeld); if (e->getName().istGleich("text")) t->addStyle(TextFeld::Style::Text); if (e->getName().istGleich("textarea")) t->addStyle(TextFeld::Style::TextGebiet); t->setText(e->getText()); if (e->hasAttribute("font-size")) t->setSchriftSize((unsigned char)(int)e->getAttributeValue("font-size")); if (e->hasAttribute("text-align-horizontal")) { if (e->getAttributeValue("text-align-horizontal").istGleich("center")) t->addStyle(TextFeld::Style::HCenter); } if (e->hasAttribute("text-align-vertical")) { if (e->getAttributeValue("text-align-vertical").istGleich("center")) t->addStyle(TextFeld::Style::VCenter); } if (e->hasAttribute("disabled")) t->removeStyle(TextFeld::Style::Editierbar); z = t; } if (e->getName().istGleich("button")) { Knopf* k = init.createKnopf(init.initParam); k->setText(e->getText()); if (e->hasAttribute("font-size")) k->setSchriftSize((unsigned char)(int)e->getAttributeValue("font-size")); z = k; } if (e->getName().istGleich("check")) { KontrollKnopf* k = init.createKontrollKnopf(init.initParam); k->setText(e->getText()); k->setSText(e->getText()); k->setStyle(KontrollKnopf::Style::Selected, e->hasAttribute("selected")); if (e->hasAttribute("font-size")) k->setSSize((unsigned char)(int)e->getAttributeValue("font-size")); z = k; } if (e->getName().istGleich("table")) { ObjTabelle* t = init.createObjTabelle(init.initParam); parseTable(e->getChilds(), t); if (e->hasAttribute("scroll")) { if (e->getAttributeValue("scroll").istGleich("horizontal")) t->addStyle(ObjTabelle::Style::HScroll); if (e->getAttributeValue("scroll").istGleich("vertical")) t->addStyle(ObjTabelle::Style::VScroll); if (e->getAttributeValue("scroll").istGleich("both")) t->addStyle(ObjTabelle::Style::scroll); } z = t; } if (e->getName().istGleich("frame")) { Fenster* f = init.createFenster(init.initParam); parseFrame(e->getChilds(), f); if (e->hasAttribute("title")) f->setTitel(e->getAttributeValue("title")); if (e->hasAttribute("title-height")) f->zTTextFeld()->setSize(f->zTTextFeld()->getBreite(), e->getAttributeValue("title-height")); z = f; } // add general attributes if (z && e->hasAttribute("tooltip")) z->setToolTipText(e->getAttributeValue("tooltip"), init.initParam.bildschirm, init.initParam.schrift); if (z && e->hasAttribute("style")) z->setStyle((__int64)e->getAttributeValue("style")); if (z && e->hasAttribute("hidden")) z->removeStyle(Zeichnung::Style::Sichtbar); if (z && e->hasAttribute("disabled")) z->removeStyle(Zeichnung::Style::Erlaubt); if (z) members->set(id, id.getLength(), z); } return z; } void UIMLView::layout(XML::Element* e, int pWidth, int pHeight) { Text id = e->getAttributeValue("id"); Zeichnung* z = members->z(id, id.getLength()); if (z) { int width = z->getBreite(); int height = z->getHeight(); if (e->hasAttribute("width")) { Text w = e->getAttributeValue("width"); width = w; if (w.getText()[w.getLength() - 1] == '%') width = (int)((pWidth / 100.0) * width); } if (e->hasAttribute("height")) { Text h = e->getAttributeValue("height"); height = h; if (h.getText()[h.getLength() - 1] == '%') height = (int)((pHeight / 100.0) * height); } z->setSize(width, height); if (e->hasAttribute("align-left")) { Text la = e->getAttributeValue("align-left"); int x = 0; if (la.istGleich("start")) x = 0; else if (la.istGleich("end")) x = pWidth; else { XML::Editor ed = e->zParent()->selectChildsByAttribute("id", la); for (auto i = ed.begin(); i; i++) layout(i, pWidth, pHeight); Zeichnung* laz = members->z(la, la.getLength()); if (laz) x = laz->getX() + laz->getBreite(); } if (e->hasAttribute("margin-left")) { Text mt = e->getAttributeValue("margin-left"); int m = mt; if (mt.getText()[mt.getLength() - 1] == '%') m = (int)((pWidth / 100.0) * m); x += m; } z->setX(x); } else if (e->hasAttribute("align-right")) { Text ra = e->getAttributeValue("align-right"); int x = 0; if (ra.istGleich("start")) x = -z->getBreite(); else if (ra.istGleich("end")) x = pWidth - z->getBreite(); else { XML::Editor ed = e->zParent()->selectChildsByAttribute("id", ra); for (auto i = ed.begin(); i; i++) layout(i, pWidth, pHeight); Zeichnung* raz = members->z(ra, ra.getLength()); if (raz) x = raz->getX() - z->getBreite(); } if (e->hasAttribute("margin-right")) { Text mt = e->getAttributeValue("margin-right"); int m = mt; if (mt.getText()[mt.getLength() - 1] == '%') m = (int)((pWidth / 100.0) * m); x -= m; } z->setX(x); } if (e->hasAttribute("align-top")) { Text ta = e->getAttributeValue("align-top"); int y = 0; if (ta.istGleich("start")) y = 0; else if (ta.istGleich("end")) y = pHeight; else { XML::Editor ed = e->zParent()->selectChildsByAttribute("id", ta); for (auto i = ed.begin(); i; i++) layout(i, pWidth, pHeight); Zeichnung* taz = members->z(ta, ta.getLength()); if (taz) y = taz->getY() + taz->getHeight(); } if (e->hasAttribute("margin-top")) { Text mt = e->getAttributeValue("margin-top"); int m = mt; if (mt.getText()[mt.getLength() - 1] == '%') m = (int)((pHeight / 100.0) * m); y += m; } z->setY(y); } else if (e->hasAttribute("align-bottom")) { Text ba = e->getAttributeValue("align-bottom"); int y = 0; if (ba.istGleich("start")) y = -z->getHeight(); else if (ba.istGleich("end")) y = pHeight - z->getHeight(); else { XML::Editor ed = e->zParent()->selectChildsByAttribute("id", ba); for (auto i = ed.begin(); i; i++) layout(i, pWidth, pHeight); Zeichnung* baz = members->z(ba, ba.getLength()); if (baz) y = baz->getY() - z->getHeight(); } if (e->hasAttribute("margin-bottom")) { Text mt = e->getAttributeValue("margin-bottom"); int m = mt; if (mt.getText()[mt.getLength() - 1] == '%') m = (int)((pHeight / 100.0) * m); y -= m; } z->setY(y); } int x = z->getX(); int y = z->getY(); if (e->hasAttribute("x")) { Text xt = e->getAttributeValue("x"); x = xt; if (xt.getText()[xt.getLength() - 1] == '%') x = (int)((pWidth / 100.0) * x); } if (e->hasAttribute("y")) { Text yt = e->getAttributeValue("y"); y = yt; if (yt.getText()[yt.getLength() - 1] == '%') y = (int)((pHeight / 100.0) * y); } z->setPosition(x, y); if (e->getName().istGleich("textarea")) { ((TextFeld*)z)->zTextRenderer()->textFormatieren(((TextFeld*)z)->zText(), z->getInnenBreite()); } } if (z) { pWidth = z->getInnenBreite(); pHeight = z->getInnenHeight(); } // recursive layout for (auto i = e->getChilds(); i; i++) layout(i, pWidth, pHeight); if (z) { if (e->getName().istGleich("table")) { ObjTabelle* objT = (ObjTabelle*)z; if (objT->getZeilenAnzahl() > 0) { if (e->hasAttribute("line-height")) { int height = e->getAttributeValue("line-height"); for (int i = 0; i < objT->getZeilenAnzahl(); i++) objT->setZeilenHeight(i, height); } for (int i = 0; i < objT->getSpaltenAnzahl(); i++) { if (objT->zZeichnung(i, 0)) objT->setSpaltenBreite(i, objT->zZeichnung(i, 0)->getBreite()); } } } } } // setzt den inhalt der view // uiml: Ein xml element gemät des ksg uiml standarts void UIMLView::setUIML(XML::Element* uiml) { if (dom) dom->release(); dom = uiml; members->leeren(); nextId = 0; if (dom) { for (auto i = dom->getChilds(); i; i++) { parseElement(i._); } } } // setzt den inhalt der view // uiml: Ein xml text gemät des ksg uiml standarts void UIMLView::setUIML(Text uiml) { setUIML(new XML::Element(uiml)); } // Gibt eine zeichnung zurück, welche in uiml eine bestimmte id hat // id: die id der Zeichnung Zeichnung* UIMLView::zZeichnung(Text id) { return members->z(id, id.getLength()); } // aktualisiert größe und position aller Zeichnungen gemäß den spezifikationen in UIML void UIMLView::layout() { if (dom) { for (auto i = dom->getChilds(); i; i++) { layout(i._, this->getInnenBreite(), this->getInnenHeight()); } } } // fügt ein element hinzu // uiml: Ein xml text gemät des KSG UIML standarts, welcher das neue Objekt darstellt Text UIMLView::addMember(Text uiml) { XML::Element* e = new XML::Element(uiml); if (parseElement(e)) dom->addChildAtFront(e); return e->getAttributeValue("id"); } // fügt ein element zu einem Elternelement hinzu (funktioniert momentan nur mit frame Objekten) // uiml: Ein xml text gemät des KSG UIML standarts, welcher das neue Objekt darstellt Text UIMLView::addMember(Text uiml, Text parentId) { XML::Element* e = new XML::Element(uiml); XML::Editor ed = dom->selectChildren(); while (ed.begin()) { XML::Editor ed2 = ed.whereAttributeEquals("id", parentId); if (ed2.begin()) { if (ed2.begin()->getName().istGleich("frame")) { Zeichnung* z = parseElement(e); if (z) { dynamic_cast(members->z(parentId, parentId.getLength()))->addMember(dynamic_cast(z->getThis())); ed2.begin()->addChild(e); } return e->getAttributeValue("id"); } } ed = ed.selectChildren(); } e->release(); return ""; } // entfernt ein element // id: id des Elements void UIMLView::removeMember(Text id) { XML::Editor e = dom->selectChildsByAttribute("id", id); e.remove(); members->remove(id, id.getLength()); } // Verarbeitet ein Tastatur Ereignis. Wird vom Framework automatisch aufgerufen // te: Das Ereignis void UIMLView::doTastaturEreignis(TastaturEreignis& te) { bool verarbeitet = te.verarbeitet; ZeichnungHintergrund::doTastaturEreignis(te); te.verarbeitet = verarbeitet; if (dom) { for (auto i = dom->getChilds(); i; i++) { // TODO render elements backwards Zeichnung* z = members->z(i->getAttributeValue("id"), i->getAttributeValue("id").getLength()); if (z) z->doTastaturEreignis(te); } } } // Updated den Zeichenhintergrund // tickVal: Die vergangene Zeit in Sekunden, die seit dem Letzten Aufruf dieser Funktion verstrichen ist // return: 1, wenn das Bild neu gezeichnet werden muss. 0 sonnst bool UIMLView::tick(double tickVal) { if (dom) { for (auto i = dom->getChilds(); i; i++) { // TODO render elements backwards Zeichnung* z = members->z(i->getAttributeValue("id"), i->getAttributeValue("id").getLength()); if (z) rend |= z->tick(tickVal); } } return ZeichnungHintergrund::tick(tickVal); } // Zeichnet den Hintergrund eines Zeichnunges nach rObj void UIMLView::render(Bild& rObj) { ZeichnungHintergrund::render(rObj); if (dom) { if (!rObj.setDrawOptions(pos.x + getRahmenBreite(), pos.y + getRahmenBreite(), gr.x + getRahmenBreite() * 2, gr.y + getRahmenBreite() * 2)) return; bool vSc = hatStyle(Style::VScroll) && vertikalScrollBar; bool hSc = hatStyle(Style::HScroll) && horizontalScrollBar; rObj.addScrollOffset(hSc ? horizontalScrollBar->getScroll() : 0, vSc ? vertikalScrollBar->getScroll() : 0); for (int i = dom->getChildCount() - 1; i >= 0; i--) { // TODO render elements backwards XML::Element* e = dom->zChild(i); Zeichnung* z = members->z(e->getAttributeValue("id"), e->getAttributeValue("id").getLength()); if (z) z->render(rObj); } rObj.releaseDrawOptions(); } } // Gibt den Dom Tree ohne erhöhten reference counter zurück // Änderungen am Dom Tree sollten vermieden werden (nur änderungen von attributen einzelner elemente sind erlaubt) XML::Element* UIMLView::zDom() const { return dom; } // Gibt den Dom Tree zurück // Änderungen am Dom Tree sollten vermieden werden (nur änderungen von attributen einzelner elemente sind erlaubt) XML::Element* UIMLView::getDom() const { return dom ? dynamic_cast(dom->getThis()) : 0; }