void setup_node( dom::element node ) { dom::element on = node.find_first("option[check='on'],options[check='on']"); dom::element off = node.find_first("option[check='off'],options[check='off']"); dom::element mixed = node.find_first("options[check='mixed']"); const wchar_t* _prev = node.get_attribute(CHECK_ATTR); std::wstring prev = _prev?_prev:L""; if( mixed.is_valid() || (on.is_valid() && off.is_valid())) { node.set_attribute(CHECK_ATTR,L"mixed"); if(prev != L"mixed") node.update(); } else if( on.is_valid() ) { node.set_attribute(CHECK_ATTR,L"on"); if(prev != L"on") node.update(); } else { node.set_attribute(CHECK_ATTR,L"off"); if(prev != L"off") node.update(); } }
void set_state(dom::element item, NODE_STATE st) { switch( st ) { case NODE_ON: item.set_attribute("check",L"on"); break; case NODE_MIXED: item.set_attribute("check",L"mixed"); break; case NODE_OFF: item.set_attribute("check",L"off"); break; } }
// select bool select_tab( dom::element& tabs_el, dom::element& tab_el ) { if(tab_el.get_state(STATE_CURRENT)) // already selected, nothing to do... return true; // but we've handled it. //find currently selected element (tab and panel) and remove "selected" from them dom::element prev_panel_el = tabs_el.find_first(":root>[name]:expanded"); dom::element prev_tab_el = tabs_el.find_first(":root>.strip>[panel]:current"); // find new tab and panel const wchar_t* pname = tab_el.get_attribute("panel"); dom::element panel_el = tabs_el.find_first(":root>[name=\"%S\"]", pname); if( !panel_el.is_valid() || !tab_el.is_valid() ) { assert(false); // panel="somename" without matching name="somename" return true; } if( prev_panel_el.is_valid() ) { prev_panel_el.set_attribute("selected", 0); // remove selected attribute - just in case somone is using attribute selectors prev_panel_el.set_state(STATE_COLLAPSED,0); // set collapsed in case of someone use it for styling } if( prev_tab_el.is_valid() ) { prev_tab_el.set_attribute("selected", 0); // remove selected attribute prev_tab_el.set_state(0,STATE_CURRENT); // reset also state flag, :current } panel_el.set_attribute("selected", L""); // set selected attribute (empty) panel_el.set_state(STATE_EXPANDED,0); // expand it tab_el.set_attribute("selected", L""); // set selected attribute (empty) tab_el.set_state(STATE_CURRENT,0); // set also state flag, :current // notify all parties involved if (prev_tab_el.is_valid()) { prev_tab_el.post_event(ELEMENT_COLLAPSED,0, prev_tab_el); // source here is old collapsed tab itself } tab_el.post_event(ELEMENT_EXPANDED,0, tab_el); // source here is new expanded tab itself // NOTE #1: these event will bubble from panel elements up to the root so panel itself, tabs ctl, its parent, etc. // will receive these notifications. Handle them if you need to change UI dependent from current tab. // NOTE #2: while handling this event in: // virtual BOOL on_event (HELEMENT he, HELEMENT target, BEHAVIOR_EVENTS type, UINT reason ), // HELEMENT target is the panel element being collapsed/expanded return true; }
//toggles checkmark void toggle_checkmark( dom::element select, dom::element item ) { const wchar_t* _old_state = item.get_attribute(CHECK_ATTR); std::wstring old_state = _old_state?_old_state:L""; if( streq(item.get_element_type(), "options")) { // non-terminal node case // inner function struct child_toggler: dom::callback { const wchar_t* state; child_toggler(const wchar_t* st): state(st) {} inline bool on_element(HELEMENT he) { htmlayout::dom::element item = he; item.set_attribute( CHECK_ATTR, state ); return false; } }; const wchar_t* new_state; NODE_STATE old_state = get_state(item); if(old_state == NODE_OFF) new_state = L"on"; else new_state = L"off"; child_toggler ct( new_state ); // do it for all children item.find_all(&ct, "option,options"); // and for itself item.set_attribute( CHECK_ATTR, new_state ); item.update(); } else if( streq(item.get_element_type(), "option")) { // terminal node const wchar_t* new_state; if(wcseq(item.get_attribute("check"),L"on")) { new_state = L"off"; } else new_state = L"on"; item.set_attribute( CHECK_ATTR, new_state ); item.update(); } // as state was changed we need to update parent chain here too. dom::element p = item.parent(); while( p.is_valid() && p != select ) { if( streq(p.get_element_type(),"options" )) { setup_node(p); } p = p.parent(); } }