#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" ) ); 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, z->getThis()->as() ); c++; } } } } void UIMLView::parseFrame( Iterator childs, Fenster *frame ) { for( auto i = childs; i; i++ ) { Zeichnung *z = parseElement( i._ ); if( z ) frame->addMember( z->getThis()->as() ); } } 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 ); 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.getIterator(); 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, z ); } return z; } void UIMLView::layout( XML::Element *e, int pWidth, int pHeight ) { Text id = e->getAttributeValue( "id" ); Zeichnung *z = members->z( id ); 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.getIterator(); i; i++ ) layout( i, pWidth, pHeight ); Zeichnung *laz = members->z( la ); 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.getIterator(); i; i++ ) layout( i, pWidth, pHeight ); Zeichnung *raz = members->z( ra ); 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.getIterator(); i; i++ ) layout( i, pWidth, pHeight ); Zeichnung *taz = members->z( ta ); 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.getIterator(); i; i++ ) layout( i, pWidth, pHeight ); Zeichnung *baz = members->z( ba ); 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 ); } // 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.getIterator() ) { XML::Editor ed2 = ed.whereAttributeEquals( "id", parentId ); if( ed2.getIterator() ) { if( ed2.getIterator()->getName().istGleich( "frame" ) ) { Zeichnung *z = parseElement( e ); if( z ) { ( (Fenster *)members->z( parentId ) )->addMember( z->getThis()->as() ); ed2.getIterator()->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 ); } // 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" ) ); 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" ) ); 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" ) ); 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 ? dom->getThis()->as() : 0; }