/************************************************************************* * sbList.cpp - current screen state controller * * author: Konstantin Maslyuk "Kalemas" mailto:kalemas@mail.ru * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. ************************************************************************/ #include "sbCore.h" #include #include #include #pragma warning ( disable : 4018 ) #pragma warning ( disable : 4996 ) // Simple cacher for sbItem class sbDrawCache { public: struct CACHE { sbItem *item; sbRect rect; int used; bool operator < (const CACHE & other) const { if (rect.top < other.rect.top) return true; return false; } }; sbDrawCache () { initialized = false; surface = NULL; } ~sbDrawCache() { if (surface != NULL) sbSurfaceDestroy(surface); } bool blit (sbSurface surf, sbItem * item, sbRect & rect) { // can place in cache if (!initialized) return false; // check if cached for ( std::list::iterator it = cache.begin(); it != cache.end(); it++ ) { if ( (*it).item == item ) { if (debug) sbMessage ("In cache %i [%i,%i] used %i\n",(*it).item,(*it).rect.top,(*it).rect.bottom,(*it).used); if ((*it).used < -500) return false; (*it).used += 3; sbBitBlt(surf,rect,surface,sbPoint((*it).rect.left,(*it).rect.top)); return true; } } // try cache sbRect place (0,0,item->width,item->height); for (std::list::iterator it = cache.begin() ; it != cache.end(); it++ ) { if ( !(place.top > (*it).rect.bottom || place.bottom < (*it).rect.top) ) { if (debug) sbMessage ("Move place in cache from %i to %i\n",place.top,(*it).rect.bottom+1); place.top = (*it).rect.bottom+1; place.bottom = place.top + item->height; } else break; } if (place.bottom > height) { if (debug) sbMessage ("Cache full\n"); full = true; return false; } // place in cache CACHE ci; ci.item = item; ci.used = 15; ci.rect = place; cache.push_back(ci); cache.sort(); if (debug) sbMessage ("Place in cache %i [%i,%i]\n",ci.item,ci.rect.top,ci.rect.bottom); item->render(surface,ci.rect); sbBitBlt(surf,rect,surface,sbPoint(ci.rect.left,ci.rect.top)); return true; } void prepare () { if (!initialized) { full = false; int memoryUse = atoi((*Core->getOptions())["General"].getWithDefault("DrawCacheSize","0")); if (memoryUse == 0) memoryUse = Core->getRect().width() * Core->getRect().height() * 3 /*bits per pixel*/ * 5 /*multiplier*/; width = Core->getRect().width(); height = memoryUse / width / 3; if (height > width) { surface = sbSurfaceCreate(width,height); sbAssert (surface == NULL); initialized = true; sbMessage ("Cache created of size %i x %i\n",width,height); debug = atoi((*Core->getOptions())["General"].getWithDefault("DrawCacheDebug","0")) == 0 ? false : true; } else { sbMessage ("Draw cache not created\n"); } } if (!initialized) return; if (debug) sbMessage ("Begin Paint\n"); //we can remove from cache only in main thread for ( std::list::iterator it = cache.begin(); it != cache.end();) { if ((*it).used < -300) { if (debug) sbMessage ("Erased %i\n",(*it).item); cache.erase(it); it = cache.begin(); } else it++; } cache.sort(); std::list::iterator useless (cache.begin()); for ( std::list::iterator it = cache.begin(); it != cache.end(); it++ ) { (*it).used--; if ((*it).used < (*useless).used) useless = it; if (debug) sbMessage ("Cache %i [%i,%i] %i\n",(*it).item,(*it).rect.top,(*it).rect.bottom,(*it).used); } if (useless != cache.end() && (full || (*useless).used < -100)) { if (debug) sbMessage ("Erased %i\n",(*useless).item); cache.erase(useless); full = false; } if (debug) sbMessage ("\n"); } void remove (sbItem * item) { if (!initialized) return; for ( std::list::iterator it = cache.begin(); it != cache.end(); it++ ) { if ((*it).item == item) { (*it).used = -1000; return; } } } private: std::list cache; sbSurface surface; int width; int height; bool initialized; bool full; bool debug; }; sbDrawCache DrawCache; sbList::sbList ( sbList::TYPE _type_ ) : type ( _type_ ) { itemCurrent = itemHover = itemEdit = itemSelected = itemBanner = itemMenu = NULL; next = prev = NULL; displace = 0.0f; module = NULL; attachedReading = attachedHistory = -1; controlSelected = -1; rect = Core->getRect(); rect.bottom -= Theme->PanelSize; switch(type) { case TYPE_SELECT_MODULE: addControl(sbControl::TYPE_OPEN_SEARCH); addControl(sbControl::TYPE_OPEN_BOOK_SELECTION); addControl(sbControl::TYPE_CLOSE); break; case TYPE_SELECT_BOOK: addControl(sbControl::TYPE_OPEN_MODULE_SELECTION); addControl(sbControl::TYPE_OPEN_SEARCH_2); addControl(sbControl::TYPE_CLOSE); break; case TYPE_SEARCH: addControl(sbControl::TYPE_OPEN_MODULE_SELECTION); addControl(sbControl::TYPE_OPEN_BOOK_SELECTION); addControl(sbControl::TYPE_CLOSE); break; case TYPE_MODULE_INSTALLER_DISCLAIMER: addControl(sbControl::TYPE_INSTALLER_DISCLAIMER_ACCEPT); addControl(sbControl::TYPE_INSTALLER_DISCLAIMER_DECLINE); break; case TYPE_MODULE_INSTALLER: addControl(sbControl::TYPE_WIDE_MODULES); break; case TYPE_MODULE_VIEW: addControl(sbControl::TYPE_OPEN_NAVIGATION_LIST); addControl(sbControl::TYPE_OPEN_OPTIONS); addControl(sbControl::TYPE_OPEN_HOME); after.constructed = before.constructed = false; break; case TYPE_READINGS: case TYPE_HISTORY: case TYPE_BOOKMARKS: case TYPE_SELECT_VERSE: addControl(sbControl::TYPE_WIDE_CLOSE); break; case TYPE_MENU_OPTIONS: addControl(sbControl::TYPE_WIDE_MODULES); break; case TYPE_HOME: addControl(sbControl::TYPE_OPEN_NAVIGATION); addControl(sbControl::TYPE_OPEN_HISTORY); addControl(sbControl::TYPE_EXIT); break; default: sbAssert ( true ); } } sbList::~sbList() { clear(); if (next != NULL) { next->prev = prev; } if (prev != NULL) { prev->next = next; } for (int i=0; i < controls.size(); i++) delete controls[i]; if (itemBanner) delete itemBanner; // remove menu if (itemMenu != NULL) { while (itemMenu->next != NULL) delete itemMenu->next; //while (itemMenu->prev != NULL) delete itemMenu->prev; delete itemMenu; itemMenu = NULL; } } void sbList::attach (sbList * list, sbList::TYPE to) { switch (to) { case PIN_PREV: if (prev != NULL) { list->prev = prev; prev->next = list; } list->next = this; prev = list; addControl(sbControl::TYPE_CAN_SWITCH_LEFT); list->addControl(sbControl::TYPE_CAN_SWITCH_RIGHT); break; case PIN_NEXT: if (next != NULL) { list->next = next; next->prev = list; } list->prev = this; next = list; addControl(sbControl::TYPE_CAN_SWITCH_RIGHT); list->addControl(sbControl::TYPE_CAN_SWITCH_LEFT); break; default: sbAssert(true); } } /* sbList::clear * empty list from items */ void sbList::clear() { if (itemCurrent != NULL) { while (itemCurrent->prev != NULL) { DrawCache.remove(itemCurrent->prev); delete itemCurrent->prev; } while (itemCurrent->next != NULL) { DrawCache.remove(itemCurrent->next); delete itemCurrent->next; } DrawCache.remove(itemCurrent); delete itemCurrent; itemCurrent = NULL; before = after = BOUND(); displace = 0; if (type == TYPE_MODULE_VIEW) before.constructed = after.constructed = false; } } /* sbList::render * draw list */ void sbList::render ( sbSurface hdc , bool showPlace , int sideDisplacement ) { sbItem *oldItem , *workItem = itemCurrent; sbRect workRect = rect, selectedRect; int screenHeight = (int)displace; workRect.left += sideDisplacement; workRect.right += sideDisplacement; Theme->drawElement ( hdc, &workRect, sbTheme::ELEMENT::BACKGROUND ); if (sideDisplacement <= 0) DrawCache.prepare(); while ( true ) { if (workItem == NULL) break; if (screenHeight > rect.bottom) break; oldItem = workItem; workRect = rect; workRect.right = sideDisplacement; // horizontal parse while (workItem != NULL) { workRect.top = screenHeight; workRect.bottom = workRect.top + workItem->height; workRect.left = workRect.right; workRect.right = workRect.left + workItem->width; if (workItem->type != sbItem::TYPE_VERSE || workItem->text.size() == 0 || workItem->expanding != 0 || !workItem->processed || Theme->fadeSurface) workItem->render(hdc,workRect); else if (!DrawCache.blit(hdc,workItem,workRect)) workItem->render(hdc,workRect); if ( workItem == itemSelected ) selectedRect = workRect; workItem = workItem->right; } workItem = oldItem; if (Theme->ListSeparatorHeight > 0 && workItem->next != NULL) { workRect.top = workRect.bottom; workRect.bottom = workRect.top + Theme->ListSeparatorHeight; workRect.left = sideDisplacement; workRect.right = sideDisplacement+rect.width(); Theme->drawElement(hdc, &workRect, sbTheme::ELEMENT::SEPARATOR); screenHeight += Theme->ListSeparatorHeight; } screenHeight += workItem->height; workItem = workItem->next; } // menu if (itemMenu != NULL) { workItem = itemMenu; workRect.top = menuPosition.y; workRect.left = menuPosition.x; workRect.right = workRect.left + workItem->width; while ( true ) { if (workItem == NULL) break; workRect.bottom = workRect.top + workItem->height; workItem->render(hdc,workRect); workRect.top = workRect.bottom; workItem = workItem->next; } } // scrolling if (itemSelected == NULL) { if (displace >= 0) { needScroll = (int)-displace; needFill = displace != 0 || screenHeight < rect.height(); } else if (screenHeight < rect.height()) { needScroll = rect.height() - screenHeight; needFill = true; } else { needScroll = 0; needFill = false; } if ((needScroll > 0 && !after.constructed) || (needScroll < 0 && !before.constructed)) needScroll = 0; } else { // selection if (selectedRect.width() > 0) { Theme->drawFrame(hdc,&selectedRect); needScroll = ((rect.height()/2)-((selectedRect.height()/2)+selectedRect.top)); } } // banner, item over the list that show current place if ( showPlace && module != NULL ) { if (itemBanner == NULL) { itemBanner = new sbItem (sbItem::LOOK_BANNER,L"",0); } if (itemBanner->index != place.Index()) { DrawCache.remove(itemBanner); sbPoint ks; const char * kt = place.getShortText(); int kl = strlen ( kt ); TCHAR * kw = new TCHAR [ kl + 1 ]; const char * mt = Core->getSword()->getModule(module)->Description(); int ml = strlen ( mt ); TCHAR * mw = new TCHAR [ ml + 1 ]; int mc = 0; TCHAR finalText [64]; mbstowcs ( kw, kt, kl+1 ); mbstowcs ( mw, mt, ml+1 ); sbSelectFont (hdc, Theme->styles[sbTheme::STYLE::CAPTION].font ); ks = sbGetTextExtent (Theme->styles[sbTheme::STYLE::CAPTION].font, kw, kl); sbSelectFont ( hdc, Theme->styles[sbTheme::STYLE::DESCRIPTION].font ); for (int width = 0; mc < ml; mc++) { sbPoint sz = sbGetTextExtent ( Theme->styles[sbTheme::STYLE::DESCRIPTION].font, mw+mc, 1 ); if ( width + sz.x > ks.x ) break; width += sz.x; } if (mc < ml && mc > 0) { mw[mc-1] = L'…'; mw[mc] = L'\0'; } _sntprintf(finalText,64,L"%s%s",kw,mw); itemBanner->index = place.Index(); itemBanner->width = ks.x + (Theme->BannerBorderSize * 2); itemBanner->setText(finalText); delete [] kw; delete [] mw; } workRect.left = (rect.width()-itemBanner->width)/2 + sideDisplacement; workRect.right = workRect.left + itemBanner->width; workRect.top = (Theme->size/6)-(itemBanner->height/2); workRect.bottom = workRect.top + itemBanner->height; if (!DrawCache.blit(hdc,itemBanner,workRect)) itemBanner->render(hdc,workRect); } } /* sbList::scroll * vertical list scrolling * return value indicates done work and necessity of redraw */ bool sbList::scroll (float amount) { //sbMessage("sbList scroll %f\n",amount); if (itemCurrent == NULL) return false; int oldDisplace = (int)displace; // don't allow scroll further then list is if (amount < 0 && itemCurrent->next == NULL && itemCurrent->height+Theme->ListSeparatorHeight+displace+amount < 0) { amount = -(itemCurrent->height+Theme->ListSeparatorHeight+displace); sbAssert (amount > 0); } if (amount > 0 && itemCurrent->prev == NULL) { amount = min(amount, rect.height()-displace); sbAssert(amount < 0); } if ( fabs(amount) > rect.height()/3 ) { amount = amount > 0.0f ? rect.height()/3.0f : -rect.height()/3.0f; } displace += amount; if ( (int)displace == (int)oldDisplace ) return false; return true; } /* sbList::getItem * get item by coordinates on screen */ sbItem * sbList::getItem (int x, int y) const { if (itemCurrent == NULL) return NULL; sbItem* i = itemCurrent; int top = (int)displace; int left = 0; if (itemMenu != NULL) { i = itemMenu; top = menuPosition.y; left = menuPosition.x; } while (i != NULL && top < rect.height()) { if (y > top && y < top + i->height) { int l = left; while (i != NULL) { if (x > l && x < l + i->width) return i; l += i->width; i = i->right; } return NULL; } top += i->height; top += Theme->ListSeparatorHeight; i = i->next; } return NULL; } /* sbList::onPressed * input */ void sbList::onPressed ( int x, int y ) { if (Core->getInput()->block) return; // if over control for(int i=controls.size()-1; i>=0; i--) if (controls[i]->hit(x,y)) return; itemHover = getItem(x,y); if (itemSelected != NULL) itemSelected = NULL; if (itemHover != NULL) { if (itemHover->type == sbItem::TYPE_VERSE) { // update current verse place.Index(itemHover->index); Core->currentVerse.copyFrom ( place ); //if (attachedReading >= 0) Core->features.updateReading(attachedReading,module->Name(),place.Index()); if (attachedHistory >= 0) Core->features.updateHistory(attachedHistory,place.Index()); } Core->redraw(); } } /* sbList::onReleased * input */ void sbList::onReleased (int x, int y) { if (Core->getInput()->block) return; if (itemHover != NULL) { itemHover = NULL; Core->redraw(); } } /* sbList::clicked * item clicked, process action by item type */ void sbList::onClicked (int x, int y) { for(int i=controls.size()-1; i>=0; i--) { if (controls[i]->hit(x,y)) { controls[i]->onPressed(); return; } } if (Core->getInput()->block) return; sbItem * item = getItem(x,y); if (item != NULL) { onItem(item); } if (itemEdit != NULL && item != itemEdit) setEditMode ( NULL ); // remove menu if (itemMenu != NULL) { while (itemMenu->next != NULL) delete itemMenu->next; //while (itemMenu->prev != NULL) delete itemMenu->prev; delete itemMenu; itemMenu = NULL; } } void sbList_Percent (char percent, void * data) { TCHAR tempText [32]; _sntprintf(tempText,32,L"Search : %i%%",percent); Core->waitMode = true; Core->waitMessage = tempText; sbUpdateScreen(); } #include void sbList::onItem ( sbItem * item ) { const int tempTextSize = 256; TCHAR tempText[tempTextSize]; switch (item->type) { case sbItem::TYPE_TEXT_FIELD: setEditMode (item); break; case sbItem::DO_SEARCH_RANGE_START: case sbItem::DO_SEARCH_RANGE_END: { sword::VerseKey workKey = Core->currentModule == NULL ? Core->defaultModule->getKey() : Core->currentModule->getKey(); if (Core->searchRange.Count() != 1) Core->searchRange = workKey.ParseVerseList("Gen-Rev",NULL,true,true); workKey.Index(item->index); if (item->type == sbItem::DO_SEARCH_RANGE_END) ((sword::VerseKey *)Core->searchRange.getElement(0))->UpperBound(workKey); else ((sword::VerseKey *)Core->searchRange.getElement(0))->LowerBound(workKey); } break; case sbItem::TYPE_START_SEARCH: { int s = sbWcsToMbs(item->prev->text.c_str()); char * request = new char [s+1]; sbWcsToMbs(item->prev->text.c_str(),request,s); sbWaitMode (true); Core->currentModule->createSearchFramework(); sbMessage ("Start search %s\n",request); sword::ListKey result = Core->currentModule->search(request,0,0,&Core->searchRange,0,sbList_Percent,request); sbItem * tempItem = item; while (item->next != NULL) delete item->next; for (int i = 0; i < result.Count(); i++) { sbMessage ("\t%s\n",result.GetElement(i)->getText()); mbstowcs(tempText,result.GetElement(i)->getText(),256); tempItem->attach(new sbItem (sbItem::TYPE_BUTTON_BOOKMARK,tempText,rect.width(),result.GetElement(i)->Index()),DIRECTION_NEXT); tempItem = tempItem->next; } Core->currentModule->deleteSearchFramework(); sbWaitMode (false); Core->waitMode = false; delete [] request; } break; case sbItem::TYPE_MODULE_INSTALLER_MODULE: case sbItem::TYPE_MODULE_INSTALLER_UPDATE: { sword::InstallSource * source = NULL; for (sbItem * i = item; i != NULL; i = i->prev) if (i->type == sbItem::TYPE_MODULE_INSTALLER_REPO) { source = (sword::InstallSource *)i->index; break; } sbAssert (source == NULL); sbWaitMode(true); int success = -1; sword::SWModule * module = ((sword::SWModule*)item->index); _sntprintf(tempText,tempTextSize,L"Dou you want to install %S of size %S KB ?\n",module->Name(),module->getConfigEntry("InstallSize")); if (sbQueryBox(tempText)) success = Core->getInstallMgr()->installModule(Core->getSword(),"",module->Name(),source); if (success >= 0) { Core->initSword(); sbWaitMode(false); Core->switchList(sbList::TYPE_SELECT_MODULE); } else sbWaitMode(false); } break; case sbItem::TYPE_MODULE_INSTALLER_REPO: { sword::InstallSource * source = (sword::InstallSource *)item->index; // repository expand / collapse if (item->next == NULL || item->next->type == sbItem::TYPE_MODULE_INSTALLER_REPO) { sword::StringList sl; std::map diff = Core->getInstallMgr()->getModuleStatus(*Core->getSword(),*source->getMgr()); sbItem * lastItem = item; for (std::map::iterator it = diff.begin(); it != diff.end(); it++) { if (std::find(sl.begin(),sl.end(),(*it).first->Type()) == sl.end()) { sl.push_back((*it).first->Type()); _sntprintf(tempText,tempTextSize,L"%S",(*it).first->Type()); lastItem->attach(sbItem::create(sbItem::LOOK_SEPARATOR,tempText,rect.width()),DIRECTION_NEXT); lastItem = lastItem->next; for (std::map::iterator im = it; im != diff.end(); im++) { if (!strcmp((*it).first->Type(),(*im).first->Type())) { if ( (*im).second & sword::InstallMgr::MODSTAT_NEW ) { _sntprintf(tempText,tempTextSize,L"%S\n%S",(*im).first->Name(),(*im).first->Description()); lastItem->attach(new sbItem (sbItem::TYPE_MODULE_INSTALLER_MODULE,tempText,rect.width(),(long)(*im).first),DIRECTION_NEXT); lastItem = lastItem->next; } else if ( (*im).second & sword::InstallMgr::MODSTAT_UPDATED ) { _sntprintf(tempText,tempTextSize,L"%S - Update\n%S",(*im).first->Name(),(*im).first->Description()); lastItem->attach(new sbItem (sbItem::TYPE_MODULE_INSTALLER_UPDATE,tempText,rect.width(),(long)(*im).first),DIRECTION_NEXT); lastItem = lastItem->next; } } } } } /*for (std::map::iterator it = diff.begin(); it != diff.end(); it++) { if ( (*it).second & sword::InstallMgr::MODSTAT_NEW ) { _sntprintf(tempText,256,L"%S\n%S\n[%S]",(*it).first->Name(),(*it).first->Description(),(*it).first->Type()); item->attach(new sbItem (sbItem::TYPE_MODULE_INSTALLER_MODULE,tempText,rect.width(),(long)(*it).first),DIRECTION_NEXT); } else if ( (*it).second & sword::InstallMgr::MODSTAT_UPDATED ) { _sntprintf(tempText,128,L"%S - Update\n%S\n[%S]",(*it).first->Name(),(*it).first->Description(),(*it).first->Type()); item->attach(new sbItem (sbItem::TYPE_MODULE_INSTALLER_UPDATE,tempText,rect.width(),(long)(*it).first),DIRECTION_NEXT); } }*/ } else { while (item->next != NULL && (item->next->type == sbItem::LOOK_SEPARATOR || item->next->type == sbItem::TYPE_MODULE_INSTALLER_MODULE || item->next->type == sbItem::TYPE_MODULE_INSTALLER_UPDATE) ) delete item->next; } } break; case sbItem::TYPE_OPEN_MODULE_INSTALLER: { if (!Core->getInstallMgr()->isUserDisclaimerConfirmed()) Core->switchList(sbList::TYPE_MODULE_INSTALLER_DISCLAIMER); else Core->switchList(sbList::TYPE_MODULE_INSTALLER); } break; case sbItem::TYPE_SWITCH_MODULE_OPTION: { // set next option value sword::StringList sl = Core->getSword()->getGlobalOptionValues(Core->moduleOptions[item->index]); const char * co = Core->getSword()->getGlobalOption(Core->moduleOptions[item->index]); sword::StringList::iterator it = std::find(sl.begin(),sl.end(),co); if (it == sl.end() || ++it == sl.end()) it = sl.begin(); Core->getSword()->setGlobalOption(Core->moduleOptions[item->index], (*it)); // update text _sntprintf(tempText,256,L"%S : %S",Core->moduleOptions[item->index],Core->getSword()->getGlobalOption(Core->moduleOptions[item->index])); item->setText(tempText); } break; case sbItem::TYPE_GOTO_MODULES: { Core->switchList(sbList::TYPE_MODULE_VIEW); } break; case sbItem::TYPE_HISTORY: case sbItem::TYPE_GO_HISTORY: { Core->goVerse = true; Core->currentModule = Core->getSword()->getModule(Core->features.history[item->index].module); Core->currentVerse.copyFrom (Core->currentModule->getKey()); Core->currentVerse.Index ( Core->features.history[item->index].placeEnd ); Core->switchList(sbList::TYPE_MODULE_VIEW); } break; case sbItem::TYPE_BUTTON_BOOKMARK: case sbItem::TYPE_BOOKMARK_VERSE_NUMBER: { Core->goVerse = true; if (Core->currentModule == NULL) { Core->currentModule = Core->defaultModule; Core->currentVerse.copyFrom(Core->defaultModule->getKey()); } Core->currentVerse.Index ( item->index ); Core->switchList(sbList::TYPE_MODULE_VIEW); } break; case sbItem::TYPE_BUTTON_SELECTION_BOOK: { if (item->next != NULL && item->next->type == sbItem::TYPE_BUTTON_SELECTION_CHAPTER) { // remove chapters while (item->next != NULL && item->next->type == sbItem::TYPE_BUTTON_SELECTION_CHAPTER) delete item->next; } else { // add chapters sbItem *tmpItem = item; sword::VerseKey workKey ( Core->currentVerse ); workKey.Index( item->index ); for (int i=0; i < workKey.getChapterMax(); i++) { workKey.setChapter(i+1); _sntprintf(tempText,tempTextSize,L"%i",workKey.getChapter()); sbItem *item = new sbItem (sbItem::TYPE_BUTTON_SELECTION_CHAPTER, tempText, rect.width()/3, workKey.Index()); if (tmpItem->type == sbItem::TYPE_BUTTON_SELECTION_CHAPTER && (tmpItem->right == NULL || tmpItem->right->right == NULL)) { sbItem *last = tmpItem; while(last->right != NULL) last = last->right; last->attach(item, DIRECTION_RIGHT); } else { tmpItem->attach (item, DIRECTION_NEXT); tmpItem = tmpItem->next; } } // add space if (tmpItem->type == sbItem::TYPE_BUTTON_SELECTION_CHAPTER) { if (tmpItem->right == NULL) tmpItem->attach(new sbItem (sbItem::DO_NONE, L"", rect.width()/3*2), DIRECTION_RIGHT); else if (tmpItem->right->right == NULL) tmpItem->right->attach(new sbItem (sbItem::DO_NONE, L"", rect.width()/3), DIRECTION_RIGHT); } } } break; case sbItem::TYPE_BUTTON_SELECTION_CHAPTER: { Core->currentVerse.Index ( item->index ); sbMessage ("Core->keypadController %i\n",Core->keypadController); if (Core->keypadController) Core->switchList(sbList::TYPE_SELECT_VERSE); else addControl((sbControl::TYPE)(sbControl::TYPE_MENU_SET_VERSE+Core->currentVerse.getVerseMax())); } break; case sbItem::TYPE_BUTTON_SELECTION_MODULE: { sword::SWModule * setModule = (sword::SWModule*) item->index; sbAssert ( setModule == NULL ); // highlighting sbItem * workItem = item; while ( workItem->prev != NULL ) workItem = workItem->prev; while ( workItem != NULL ) { workItem->highlighted = false; workItem = workItem->next; } item->highlighted = true; Core->goVerse = true; Core->currentModule = setModule; Core->currentModule->setKey ( Core->currentVerse ); Core->currentVerse.copyFrom ( Core->currentModule->getKey() ); Core->redraw(); } break; } } /* sbList::onTapped * input */ void sbList::onTapped ( int x, int y ) { if (Core->getInput()->block) return; sbItem * item = getItem(x,y); if (item == NULL) return; if (item->type == sbItem::TYPE_VERSE) { addControl(sbControl::TYPE_MENU_VERSE); } else if (item->type == sbItem::TYPE_BUTTON_SELECTION_BOOK || item->type == sbItem::TYPE_BUTTON_SELECTION_CHAPTER) { sbAssert (itemMenu != NULL); itemMenu = new sbItem (sbItem::DO_SEARCH_RANGE_START,L"Search from",rect.width()/2,item->index); itemMenu->attach(new sbItem (sbItem::DO_SEARCH_RANGE_END,L"Search to",rect.width()/2,item->index),DIRECTION_NEXT); menuPosition = sbPoint (max(Theme->size/10,x-itemMenu->width),max(Theme->size/10,y-itemMenu->height-itemMenu->next->height)); } } /* sbList::process * fill verses with text from module * also delete unnecessary items */ void sbList::process ( bool * abort ) { sbAssert ( type != sbList::TYPE_MODULE_VIEW ); sword::SWModule * mod = Core->getSword()->getModule(module); sbAssert ( module == NULL ); sbAssert ( mod == NULL ); sword::VerseKey workKey ( place ); if (itemCurrent == NULL) return; while ( ! * abort ) { int displace = (int)sbList::displace; sbItem * item = itemCurrent; bool atEnd = false; // delete unnecessary items, it should be in background thread ... if ( before.verseCount + after.verseCount > Core->versesOptimal ) { int countDeleted = 0; int needDelete = ( before.verseCount + after.verseCount ) / Core->versesOptimal * 10; if ( after.verseCount > before.verseCount ) { while ( countDeleted < needDelete ) { after.verse = after.verse->prev; while (after.verse->type != sbItem::TYPE_VERSE) after.verse = after.verse->prev; while (after.verse->next != NULL) { DrawCache.remove(after.verse->next); delete after.verse->next; } countDeleted++; } if ( after.constructed ) after.constructed = false; after.verseCount -= countDeleted; } else { while ( countDeleted < needDelete ) { before.verse = before.verse->next; while (before.verse->type != sbItem::TYPE_VERSE) before.verse = before.verse->next; while (before.verse->prev != NULL) { DrawCache.remove(before.verse->prev); delete before.verse->prev; } countDeleted++; } if ( before.constructed ) before.constructed = false; before.verseCount -= countDeleted; } } // find center screen item while (item->next != NULL && displace+item->height < (rect.height())/2) { displace += item->height; item = item->next; } sbItem * last = item; sbItem * first = item; while ( ! * abort ) { if ( item->type == sbItem::TYPE_VERSE && item->processed == false ) { DrawCache.remove(item); workKey.Index ( item->index ); mod->SetKey ( workKey ); TCHAR * text = (TCHAR*) mod->RenderText(); int length = _tcslen ( text ); if ( length == 0 ) break; int oldHeight = item->height; item->setText ( text ); item->expanding = item->height; item->height = oldHeight; item->processed = true; break; // start again } if (atEnd && last->next != NULL) { last = last->next; item = last; displace += item->height; } else if (first->prev != NULL) { first = first->prev; item = first; displace -= item->height; } else { sbSleep(50); // there should be sleep in thread, so thread will not grab all system resources break; } atEnd = ! atEnd; } } sbAssert ( ! abort ); sbMessage ("sbList : thread stoped.\n"); } /* * sbList::controlPressed * process action for pressed control */ bool sbList::onControl ( sbControl::TYPE type ) { switch ( type ) { case sbControl::TYPE_MENU_VERSE_ADD_DYNAMIC_BOOKMARK: case sbControl::TYPE_MENU_VERSE_ADD_STATIC_BOOKMARK: removeControl ( sbControl::TYPE_MENU_CURRENT ); break; case sbControl::TYPE_MENU_VERSE_START_EDITING: { sbItem* item = itemCurrent; while (item->next != NULL) if (item->index == place.Index() && item->type == sbItem::TYPE_VERSE) break; else item = item->next; sbAssert ( item == NULL ); setEditMode ( item ); removeControl ( sbControl::TYPE_MENU_CURRENT ); } break; case sbControl::TYPE_MENU_EXIT_NO: case sbControl::TYPE_MENU_CANCEL: removeControl ( sbControl::TYPE_MENU_CURRENT ); break; case sbControl::TYPE_EXIT: addControl ( sbControl::TYPE_MENU_EXIT ); break; case sbControl::TYPE_MENU_EXIT: case sbControl::TYPE_MENU_VERSE: removeControl ( type ); break; default: if (type >= sbControl::TYPE_SET_VERSE && type < sbControl::TYPE_SET_VERSE_MAX) { sbAssert ( this->type != sbList::TYPE_SELECT_BOOK ); Core->goVerse = true; Core->currentVerse.setVerse ( type - sbControl::TYPE_SET_VERSE ); if (Core->currentModule == NULL) Core->currentModule = Core->defaultModule; removeControl ( sbControl::TYPE_MENU_CURRENT ); Core->switchList ( sbList::TYPE_MODULE_VIEW ); } else if (type >= sbControl::TYPE_MENU_SET_VERSE && type < sbControl::TYPE_MENU_SET_VERSE_MAX) { removeControl ( type ); } else { return false; } } return true; } void sbList::addControl ( sbControl::TYPE type ) { for (int i=0; i < controls.size(); i++) if (controls[i]->type == type) return; controls.push_back ( new sbControl ( type ) ); if ( controls.back()->isMenu() ) { sbAssert(Theme->fadeSurface || Core->getInput()->block); Theme->fadeSurface = true; Core->getInput()->block = true; } } void sbList::removeControl ( sbControl::TYPE type ) { for (std::vector::iterator it=controls.begin(); it != controls.end(); it++) { if ((*it)->type == type || ((*it)->isMenu() && type == sbControl::TYPE_MENU_CURRENT)) { if ((*it)->isMenu()) { sbAssert(!Theme->fadeSurface || !Core->getInput()->block); Theme->fadeSurface = false; Core->getInput()->block = false; } controls.erase(it); return; } } } void sbList::onTimer ( const int timer ) { switch (timer) { case sbCore::TIMER_REDRAW: { //static int c = 0; if (c++ < 20) return; c = 0; // Expand items heights if ( itemCurrent != NULL && type == sbList::TYPE_MODULE_VIEW ) { const int halfscreen = rect.height()/2; for ( int direction = 0; direction < 2; direction++ ) { sbItem * item = itemCurrent; int y = (int)displace; while ( item != NULL ) { if ( item->expanding != 0 && !( direction == 1 && item == itemCurrent ) ) { // out of screen if ( y < -(item->height+Theme->ListSeparatorHeight) || y > rect.height() ) { item->height = item->expanding; item->expanding = 0; } else { const int add = min((int)ceil((item->expanding-item->height)*0.2f),item->expanding-item->height); item->height += add; Core->redraw(); if ( item->height >= item->expanding ) { sbAssert(item->height > item->expanding); item->height = item->expanding; item->expanding = 0; } if ( y < halfscreen ) { if ( y + item->height < halfscreen ) { scroll ( (float)-add ); y -= add; } else { const float cd = add * ((halfscreen-y)/(float)halfscreen); scroll ( -cd ); y -= (int)cd; } } } } if ( direction > 0 ) { y += item->height; item = item->next; } else { item = item->prev; if ( item != NULL ) y -= item->height; } } } } } break; case sbCore::TIMER_BEFORE_REDRAW: { const int tempTextSize = 72; TCHAR tempText [tempTextSize]; // add blank verses if ( type == sbList::TYPE_MODULE_VIEW && module != NULL ) { sword::VerseKey workKey ( place ); int added = 0; if (itemCurrent == NULL) { _sntprintf(tempText,tempTextSize,L"%i",workKey.getVerse()); itemCurrent = new sbItem (sbItem::TYPE_VERSE, tempText, rect.width(), workKey.Index()); before.verse = itemCurrent; after.verse = itemCurrent; if (workKey.getVerse() == 1) { _sntprintf(tempText,tempTextSize,L"%S %i",workKey.getBookName(),workKey.getChapter()); itemCurrent->attach(new sbItem (sbItem::LOOK_CAPTION, tempText, rect.width(), workKey.Index()), DIRECTION_PREV); } added++; needFill = true; } while (true) { bool atEnd; if (after.verseCount+before.verseCount > Core->versesMax) { sbSleep(25); break; } // need for memory reason if (after.verseCount+before.verseCount > Core->versesOptimal * 2) sbSleep(5); if (after.verseCount < 15 && !after.constructed) atEnd = true; else if (before.verseCount < 5 && !before.constructed) atEnd = false; else if (added > 4) break; else { if (before.verseCount+after.verseCount > Core->versesOptimal/2) break; atEnd = added%2==0; if ((after.constructed && atEnd) || (before.constructed && !atEnd)) { added++; continue; } } sbItem* item = atEnd ? after.verse : before.verse; int index = 0; while (true) { if (item->type == sbItem::TYPE_VERSE) index = item->index; if (atEnd ? item->next == NULL : item->prev == NULL) break; item = atEnd ? item->next : item->prev; } workKey.Index(index); atEnd ? workKey.increment() : workKey.decrement(); if (workKey.Index() != index) { _sntprintf(tempText,tempTextSize,L"%i",workKey.getVerse()); item->attach(new sbItem (sbItem::TYPE_VERSE, tempText, rect.width(), workKey.Index()), atEnd ? DIRECTION_NEXT : DIRECTION_PREV); if (atEnd) { after.verse = item->next; after.verseCount++; } else { before.verse = item->prev; before.verseCount++; } if (workKey.getVerse() == 1) { _sntprintf(tempText,tempTextSize,L"%S %i",workKey.getBookName(),workKey.getChapter()); if (atEnd) { after.verse->attach(new sbItem (sbItem::LOOK_CAPTION, tempText, rect.width(), workKey.Index()), DIRECTION_PREV); } else { before.verse->attach(new sbItem (sbItem::LOOK_CAPTION, tempText, rect.width(), workKey.Index()), DIRECTION_PREV); } } added++; } else { atEnd ? after.constructed = true : before.constructed = true; } } } // itemCurrent may be not first on screen, so do correction if ( itemCurrent != NULL ) { while (displace > -Theme->ListSeparatorHeight && itemCurrent->prev != NULL) { if (itemCurrent->type == sbItem::TYPE_VERSE) { before.verseCount--; after.verseCount++; } itemCurrent = itemCurrent->prev; displace -= itemCurrent->height + Theme->ListSeparatorHeight; } while (displace < 0 && fabs(displace) > itemCurrent->height + Theme->ListSeparatorHeight) { if (itemCurrent->next == NULL) break; displace += itemCurrent->height + Theme->ListSeparatorHeight; if (itemCurrent->type == sbItem::TYPE_VERSE) { before.verseCount++; after.verseCount--; } itemCurrent = itemCurrent->next; } } } break; } } /* sbList::onActivate * called before first redraw */ void sbList::onActivate ( ) { const int tempTextSize = 256; static TCHAR tempText [tempTextSize]; sbSetSip ( itemEdit != NULL ); itemSelected = NULL; switch (type) { case TYPE_SEARCH: { if (Core->currentModule != NULL) { if (!Core->searchRange.Count()) { sword::VerseKey workKey = Core->currentModule->getKey(); Core->searchRange = workKey.ParseVerseList("Gen-Rev",NULL,true,true); } if (itemCurrent == NULL || itemCurrent->type == sbItem::DO_NONE) { clear(); itemCurrent = new sbItem (sbItem::TYPE_TEXT_FIELD,L"",rect.width()); itemCurrent->attach(new sbItem (sbItem::TYPE_START_SEARCH,L"",rect.width()),DIRECTION_NEXT); } _sntprintf(tempText,tempTextSize,L"Search ...\n%S in %S",Core->currentModule->Name(),Core->searchRange.getRangeText()); itemCurrent->getItem(sbItem::TYPE_START_SEARCH)->setText(tempText); } else { itemCurrent = new sbItem (sbItem::DO_NONE,L"No Module Selected",rect.width()); } } break; case TYPE_MODULE_INSTALLER_DISCLAIMER: { clear(); itemCurrent = new sbItem (sbItem::DO_NONE,L"WARNING\n \nAlthough Install Manager provides a convenient way for installing and upgrading SWORD components, it also uses a systematic method for accessing sites which gives packet sniffers a target to lock into for singling out users.\n \nIF YOU LIVE IN A PERSECUTED COUNTRY AND DO NOT WISH TO RISK DETECTION, YOU SHOULD NOT USE INSTALL MANAGER'S REMOTE SOURCE FEATURES.\n \nAlso, Remote Sources other than CrossWire may contain less than quality modules, modules with unorthodox content, or even modules which are not legitimately distributable. Many repositories contain wonderfully useful content. These repositories simply are not reviewed or maintained by CrossWire and CrossWire cannot be held responsible for their content.\n \nIf you understand this and are willing to enable remote source features then type yes at the prompt.",rect.width()); } break; case TYPE_MODULE_INSTALLER: { sbItem * tempItem; bool refreshed = atoi((*Core->getInstallMgr()->installConf)["General"].getWithDefault("Refreshed","0")) == 0 ? false : true; clear(); sbWaitMode ( true ); int success; if (!refreshed) success = Core->getInstallMgr()->refreshRemoteSourceConfiguration(); if (success != 0) sbMessage ("Install Manager Refresh Sources : %i\n",success); tempItem = itemCurrent = sbItem::create(sbItem::LOOK_SEPARATOR,L"Available repositories:",rect.width()); for (sword::InstallSourceMap::iterator it = Core->getInstallMgr()->sources.begin(); it != Core->getInstallMgr()->sources.end(); it++) { _sntprintf(tempText,tempTextSize,L"%S",(*it).second->caption); tempItem->attach(sbItem::create(sbItem::TYPE_MODULE_INSTALLER_REPO,tempText,rect.width(),(long)(*it).second),DIRECTION_NEXT); tempItem = tempItem->next; if (!refreshed) Core->getInstallMgr()->refreshRemoteSource((*it).second); Core->getInstallMgr()->getModuleStatus(*Core->getSword(),*(*it).second->getMgr()); } sbWaitMode ( false ); if (Core->getInstallMgr()->sources.size() > 0) (*Core->getInstallMgr()->installConf)["General"]["Refreshed"] = "1"; } break; case TYPE_MENU_OPTIONS: { clear(); itemCurrent = new sbItem(sbItem::LOOK_SEPARATOR,L"Module Options :",rect.width()); for (int i = 0; i < Core->moduleOptions.size(); i++) { _sntprintf(tempText,tempTextSize,L"%S : %S",Core->moduleOptions[i],Core->getSword()->getGlobalOption(Core->moduleOptions[i])); sbItem * item = new sbItem(sbItem::TYPE_SWITCH_MODULE_OPTION,tempText,rect.width(),i); itemCurrent->attach(item,DIRECTION_NEXT); itemCurrent = itemCurrent->next; } while (itemCurrent->prev != NULL) itemCurrent = itemCurrent->prev; Core->changedGlobalOptions = true; } break; case TYPE_SELECT_VERSE: { clear (); _sntprintf(tempText,tempTextSize,L"%S %i",Core->currentVerse.getBookName(),Core->currentVerse.getChapter()); itemCurrent = new sbItem (sbItem::DO_NONE, tempText, rect.width(), Core->currentVerse.Index()); // add verses sbItem * tempItem = itemCurrent; sword::VerseKey workKey ( Core->currentVerse ); for (int i=0; i < workKey.getVerseMax(); i++) { workKey.setVerse(i+1); _sntprintf(tempText,tempTextSize,L"%i",workKey.getVerse()); sbItem * item = new sbItem (sbItem::TYPE_BOOKMARK_VERSE_NUMBER, tempText, rect.width()/4, workKey.Index()); if (tempItem->type == sbItem::TYPE_BOOKMARK_VERSE_NUMBER && (tempItem->right == NULL || tempItem->right->right == NULL || tempItem->right->right->right == NULL)) { sbItem *last = tempItem; while(last->right != NULL) last = last->right; last->attach(item, DIRECTION_RIGHT); } else { tempItem->attach (item, DIRECTION_NEXT); tempItem = tempItem->next; } } // add space if (tempItem->type == sbItem::TYPE_BOOKMARK_VERSE_NUMBER) { if (tempItem->right == NULL) tempItem->attach(new sbItem (sbItem::DO_NONE, L"", rect.width()/4*3), DIRECTION_RIGHT); else if (tempItem->right->right == NULL) tempItem->right->attach(new sbItem (sbItem::DO_NONE, L"", rect.width()/4*2), DIRECTION_RIGHT); else if (tempItem->right->right->right == NULL) tempItem->right->right->attach(new sbItem (sbItem::DO_NONE, L"", rect.width()/4), DIRECTION_RIGHT); } } break; case TYPE_HOME: { clear(); itemCurrent = new sbItem (sbItem::DO_NONE, L"Welcome to\nSlideBible Beta!", rect.width()); if ( Core->defaultModule != NULL ) { sword::VerseKey workKey ( Core->defaultModule->getKey() ); if ( Core->currentModule != NULL ) // here we should check last active module view { _sntprintf(tempText,tempTextSize,L" \nReturn to %S\n ",Core->currentVerse.getText()); itemCurrent->attach(new sbItem (sbItem::TYPE_GOTO_MODULES, tempText, rect.width()), DIRECTION_NEXT); itemCurrent = itemCurrent->next; } else if (Core->features.history.size() > 0) { workKey.copyFrom(Core->getSword()->getModule(Core->features.history.back().module)->getKey()); workKey.Index(Core->features.history.back().placeEnd); _sntprintf(tempText,tempTextSize,L" \nContinue read from %S\n ",workKey.getText()); itemCurrent->attach(new sbItem (sbItem::TYPE_GO_HISTORY, tempText, rect.width(), Core->features.history.size()-1), DIRECTION_NEXT); itemCurrent = itemCurrent->next; } else { workKey.setText ( "John 1:1" ); itemCurrent->attach(new sbItem (sbItem::TYPE_BUTTON_BOOKMARK, L" \nRead Bible ...\n ", rect.width(), workKey.Index()), DIRECTION_NEXT); itemCurrent = itemCurrent->next; } } else { itemCurrent->attach (new sbItem (sbItem::DO_NONE, L"No modules Found!\n\nPlease download any Bible module from www.crosswire.org and put \"mods.d\" and \"modules\" folders into application folder.", rect.width()), DIRECTION_NEXT); itemCurrent = itemCurrent->next; itemCurrent->attach (new sbItem (sbItem::TYPE_OPEN_MODULE_INSTALLER,L"Install Modules ...", rect.width()),DIRECTION_NEXT); itemCurrent = itemCurrent->next; } _sntprintf(tempText,tempTextSize,L"About :\nBuilt on %S\nUsing SWORD version %S",__DATE__,sword::SWVersion::currentVersion.getText()); itemCurrent->attach(new sbItem (sbItem::DO_NONE, tempText, rect.width()), DIRECTION_NEXT); itemCurrent = itemCurrent->next; while ( itemCurrent->prev != NULL ) itemCurrent = itemCurrent->prev; } break; case TYPE_MODULE_VIEW: { if (Core->goVerse) { Core->goVerse = false; sbAssert ( Core->currentModule == NULL ); module = Core->holdString(Core->currentModule->Name()); clear(); place.copyFrom ( Core->currentVerse ); if (itemBanner) { DrawCache.remove(itemBanner); delete itemBanner; itemBanner = NULL; } displace = rect.height()*2.0f/5.0f; // adding blank verses starts automatically in sbList::onTimer(sbCore::TIMER_BEFORE_REDRAW) // filling with text occurs in sbList::process in another thread // update history attachedHistory = Core->features.addHistory(module,place.Index()); Core->redraw(); if (options.size() != Core->moduleOptions.size()) { options.resize(Core->moduleOptions.size()); for (int i=0; imoduleOptions.size(); i++) { options[i] = Core->holdString(Core->getSword()->getGlobalOption(Core->moduleOptions[i])); } } } if (module != NULL) { if (next == NULL) attach (new sbList(sbList::TYPE_MODULE_VIEW), sbList::PIN_NEXT); if (prev == NULL) attach (new sbList(sbList::TYPE_MODULE_VIEW), sbList::PIN_PREV); // if global options changed , reprocess items text bool needReprocess = false; if (!Core->changedGlobalOptions) { for (int i = 0; i < options.size(); i++) Core->getSword()->setGlobalOption(Core->moduleOptions[i],options[i]); } for (int i=0; i < Core->moduleOptions.size(); i++) { if (strcmp(Core->getSword()->getGlobalOption(Core->moduleOptions[i]),options[i])) { needReprocess = true; options[i] = Core->holdString(Core->getSword()->getGlobalOption(Core->moduleOptions[i])); } } if (needReprocess) { for (sbItem * item = itemCurrent; item != NULL; item = item->next) item->processed = false; for (sbItem * item = itemCurrent; item != NULL; item = item->prev) item->processed = false; } //Core->threadCreate(this); Core->currentModule = Core->getSword()->getModule(module); Core->currentVerse.copyFrom ( place ); Core->changedGlobalOptions = false; } } break; case TYPE_SELECT_BOOK: { sbItem * setItem = NULL; int t = 0; sword::VerseKey workKey ( Core->currentVerse ); const char * moduleBook = workKey.getBookName(); clear(); workKey.setPosition(sword::TOP); while ( true ) { _sntprintf(tempText,tempTextSize,L"%S",workKey.getBookName()); sbItem *item = new sbItem (sbItem::TYPE_BUTTON_SELECTION_BOOK, tempText, rect.width(), workKey.Index()); if (moduleBook == workKey.getBookName()) setItem = item; if (itemCurrent == NULL) { itemCurrent = item; } else { itemCurrent->attach (item, DIRECTION_NEXT); itemCurrent = itemCurrent->next; } // testament separator if (t != workKey.getTestament()) { if (t == 0) itemCurrent->attach(sbItem::create(sbItem::LOOK_SEPARATOR,L"Old Testament",rect.width()),DIRECTION_PREV); else if (t == 1) itemCurrent->attach(sbItem::create(sbItem::LOOK_SEPARATOR,L"New Testament",rect.width()),DIRECTION_PREV); t = workKey.getTestament(); } // next book int b = workKey.getBook(); workKey.setBook(workKey.getBook()+1); if (b == workKey.getBook()) break; } if (setItem != NULL) { if (setItem->prev != NULL && setItem->prev->type == sbItem::LOOK_SEPARATOR) itemCurrent = setItem->prev; else itemCurrent = setItem; } else while (itemCurrent->prev != NULL) itemCurrent = itemCurrent->prev; } break; case TYPE_SELECT_MODULE: { clear(); sword::StringList sl; sbItem * tempItem; for (sword::ModMap::iterator it = Core->getSword()->Modules.begin(); it != Core->getSword()->Modules.end(); it++) { if (std::find(sl.begin(),sl.end(),(*it).second->Type()) == sl.end()) { sl.push_back((*it).second->Type()); _sntprintf(tempText,tempTextSize,L"%S",(*it).second->Type()); tempItem = sbItem::create(sbItem::LOOK_SEPARATOR,tempText,rect.width()); if (itemCurrent == NULL) itemCurrent = tempItem; else itemCurrent->attach(tempItem,DIRECTION_NEXT), itemCurrent = itemCurrent->next; for (sword::ModMap::iterator im = it; im != Core->getSword()->Modules.end(); im++) { if (!strcmp((*it).second->Type(),(*im).second->Type())) { _sntprintf(tempText,tempTextSize,L"%S\n%S",(*im).second->Name(),(*im).second->Description()); itemCurrent->attach(new sbItem (sbItem::TYPE_BUTTON_SELECTION_MODULE, tempText, rect.width(), (long)(*im).second),DIRECTION_NEXT); itemCurrent = itemCurrent->next; if (Core->currentModule == (*im).second) itemCurrent->highlighted = true; } } } } tempItem = sbItem::create (sbItem::TYPE_OPEN_MODULE_INSTALLER, L"Install Modules ...", rect.width()); itemCurrent == NULL ? itemCurrent = tempItem : itemCurrent->attach(tempItem,DIRECTION_NEXT); while (itemCurrent->prev != NULL) itemCurrent = itemCurrent->prev; } break; case TYPE_HISTORY: { bool createdNow = false; bool createdToday = false; bool createdYesterday = false; bool createdWeek = false; bool createdOlder = false; time_t startedToday; time_t startedYesterday; time_t startedWeek; time(&startedToday); tm date = *localtime(&startedToday); date.tm_hour = 0; date.tm_min = 0; date.tm_sec = 0; startedToday = mktime(&date); date.tm_mday -= 1; startedYesterday = mktime(&date); date.tm_mday -= 6; startedWeek = mktime(&date); clear(); for (int h = Core->features.history.size()-1; h >= 0 && Core->features.history.size()-h <= 50 ; h--) { sbFeatures::History * hi = &Core->features.history[h]; sword::VerseKey workKey ( Core->getSword()->getModule(hi->module)->getKey() ); workKey.Index (hi->placeEnd); _sntprintf(tempText,tempTextSize,L"%S\n%i:%i\n%S",workKey.getBookName(),workKey.getChapter(),workKey.getVerse(),hi->module); sbItem * timeHeader = NULL; if (hi->visitStart > Core->systemStarted) { if(!createdNow) { timeHeader = new sbItem (sbItem::LOOK_SEPARATOR, L"Now", rect.width()); createdNow = true; } } else if (hi->visitStart > startedToday) { if(!createdToday) { timeHeader = new sbItem (sbItem::LOOK_SEPARATOR, L"Today", rect.width()); createdToday = true; } } else if (hi->visitStart > startedYesterday) { if(!createdYesterday) { timeHeader = new sbItem (sbItem::LOOK_SEPARATOR, L"Yesterday", rect.width()); createdYesterday = true; } } else if (hi->visitStart > startedWeek) { if(!createdWeek) { timeHeader = new sbItem (sbItem::LOOK_SEPARATOR, L"Last Week", rect.width()); createdWeek = true; } } else if (!createdOlder) { timeHeader = new sbItem (sbItem::LOOK_SEPARATOR, L"Older", rect.width()); createdOlder = true; } if (timeHeader != NULL) { if ( itemCurrent == NULL ) { itemCurrent = timeHeader; } else { itemCurrent->attach(timeHeader,DIRECTION_NEXT); itemCurrent = itemCurrent->next; } } sbItem * item = new sbItem (sbItem::TYPE_HISTORY, tempText, rect.width(), h); if ( itemCurrent == NULL ) { itemCurrent = item; } else { itemCurrent->attach(item,DIRECTION_NEXT); itemCurrent = itemCurrent->next; } } if ( itemCurrent != NULL ) while ( itemCurrent->prev != NULL ) itemCurrent = itemCurrent->prev; } break; default: ; } } /* sbList::setEditMode * controls list edit mode */ void sbList::setEditMode ( sbItem * item ) { if ( item == NULL && itemEdit != NULL ) { // finish edit , reallocate text itemEdit = NULL; sbSetSip (false); } else if (item != NULL) { // start edit itemEdit = item; itemEditCursor = itemEdit->text.size(); sbSetSip (true); } else sbAssert(true); } bool sbList::onChar ( TCHAR character ) { if (itemEdit != NULL) { static std::wstring text; if (character == 0x08) { if (itemEdit->text.size() > 0) { text = itemEdit->text; text.erase(--itemEditCursor); } } else { TCHAR str [2] = {character,L'\0'}; text = itemEdit->text; text.insert(itemEditCursor++, str); } itemEdit->setText(text.c_str()); Core->redraw(); return true; } return false; } bool sbList::onKey ( int key ) { switch ( key ) { case 0x0D: //VK_RETURN if (itemSelected != NULL) { onItem(itemSelected); Core->redraw(); } if (controlSelected != -1) { controls[controlSelected]->onPressed(); } break; case 0x25: // VK_LEFT if (itemSelected == NULL && controlSelected == 0 && type == sbList::TYPE_MODULE_VIEW) { Core->switchList(PIN_PREV); } else { if (itemSelected != NULL && itemSelected->left != NULL) { itemSelected = itemSelected->left; } else { itemSelected = NULL; if (controlSelected == -1) controlSelected = controls.size()-1; else if (controlSelected > 0) controlSelected--; } Core->redraw(); } return true; case 0x27: // VK_RIGHT if (itemSelected == NULL && controlSelected == controls.size()-1 && type == sbList::TYPE_MODULE_VIEW) { Core->switchList(PIN_NEXT); } else { if (itemSelected != NULL && itemSelected->right != NULL) { itemSelected = itemSelected->right; } else { itemSelected = NULL; if (controlSelected == -1) controlSelected = controls.size()-1; else if (controlSelected < controls.size()-1) controlSelected++; } Core->redraw(); } break; case 0x28: // VK_DOWN if ( itemSelected == NULL ) itemSelected = itemCurrent; else if ( itemSelected->next != NULL ) itemSelected = itemSelected->next; controlSelected = -1; Core->redraw(); break; case 0x26: // VK_UP if ( itemSelected == NULL ) itemSelected = itemCurrent; else if ( itemSelected->prev != NULL ) itemSelected = itemSelected->prev; controlSelected = -1; Core->redraw(); break; case 0x1B: // VK_ESCAPE sbExit(1); break; /* case 0x44: // VK_D Core->initSword(); break; case 0x42: // VK_B sbAssert(true); break; */ default: return false; } return true; }