From d0ff61807db84cc3de5c51083a9c5ee0258163fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Tue, 6 Jul 2010 02:10:26 +0000 Subject: [PATCH] Obtaining town instance pointer via cb. Plz, don't access gamestate directly from player interface! Everything has to go via callback. Commented out giving starting artifact - new artifact randomization make it crashing. Please fix it. New control - CTextBox - for multi-line text with optional slider. Used it for map description and info windows. Related changes. Fixes #22 and #96. --- CCallback.cpp | 19 ++- CCallback.h | 4 +- client/AdventureMapButton.cpp | 43 +++++++ client/AdventureMapButton.h | 18 +-- client/CCastleInterface.cpp | 2 +- client/CHeroWindow.cpp | 20 ++-- client/CKingdomInterface.cpp | 16 ++- client/CMessage.cpp | 216 ++++++++++++---------------------- client/CMessage.h | 6 +- client/CPreGame.cpp | 64 +++++----- client/CPreGame.h | 5 +- client/FontBase.h | 20 ++++ client/GUIBase.cpp | 167 ++++++++++++++++++-------- client/GUIBase.h | 43 +++++-- client/GUIClasses.cpp | 173 +++++++++++++++++++-------- client/GUIClasses.h | 40 +++++-- client/Graphics.cpp | 7 ++ client/Graphics.h | 19 --- client/SDL_Extensions.cpp | 30 ++--- hch/CObjectHandler.cpp | 6 +- lib/CGameState.cpp | 38 +++--- lib/map.cpp | 2 +- 22 files changed, 568 insertions(+), 390 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 365f3e7d7..210d1d391 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -164,17 +164,15 @@ const CGTownInstance * CCallback::getTownInfo(int val, bool mode) const //mode = else return NULL; } - else + else if(mode == 1) { - //TODO: add some smart ID to the CTownInstance - - - //for (int i=0; iplayers[gs->currentPlayer].towns.size();i++) - //{ - // if (gs->players[gs->currentPlayer].towns[i]->someID==val) - // return gs->players[gs->currentPlayer].towns[i]; - //} - return NULL; + const CGObjectInstance *obj = getObjectInfo(val); + if(!obj) + return NULL; + if(obj->ID != TOWNI_TYPE) + return NULL; + else + return static_cast(obj); } return NULL; } @@ -241,6 +239,7 @@ const CGHeroInstance * CCallback::getHeroInfo(int val, int mode) const //mode = const CGObjectInstance * CCallback::getObjectInfo(int ID) const { + //TODO: check for visibility return gs->map->objects[ID]; } diff --git a/CCallback.h b/CCallback.h index 3e14939e7..6e88781b3 100644 --- a/CCallback.h +++ b/CCallback.h @@ -141,7 +141,7 @@ public: //town virtual int howManyTowns()const =0; - virtual const CGTownInstance * getTownInfo(int val, bool mode)const =0; //mode = 0 -> val = serial; mode = 1 -> val = ID + virtual const CGTownInstance * getTownInfo(int val, bool mode)const =0; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial) virtual std::vector < const CGTownInstance *> getTownsInfo(bool onlyOur=true) const=0; virtual std::vector getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited virtual int canBuildStructure(const CGTownInstance *t, int ID) =0;//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements @@ -245,7 +245,7 @@ public: int getResourceAmount(int type) const; std::vector getResourceAmount() const; int howManyHeroes(bool includeGarrisoned = true) const; - const CGTownInstance * getTownInfo(int val, bool mode) const; //mode = 0 -> val = serial; mode = 1 -> val = ID + const CGTownInstance * getTownInfo(int val, bool mode) const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial) std::vector < const CGTownInstance *> getTownsInfo(bool onlyOur=true) const; int howManyTowns()const; std::vector < std::string > getObjDescriptions(int3 pos) const; //returns descriptions of objects at pos in order from the lowest to the highest diff --git a/client/AdventureMapButton.cpp b/client/AdventureMapButton.cpp index 06211e755..6482f81d5 100644 --- a/client/AdventureMapButton.cpp +++ b/client/AdventureMapButton.cpp @@ -637,3 +637,46 @@ void CSlider::setAmount( int to ) positions = to - capacity; amax(positions, 0); } + +void CSlider::showAll(SDL_Surface * to) +{ + SDL_FillRect(to, &pos, 0); + CIntObject::showAll(to); +} + +void CSlider::wheelScrolled(bool down, bool in) +{ + moveTo(value + 3 * (down ? +1 : -1)); +} + +void CSlider::keyPressed(const SDL_KeyboardEvent & key) +{ + if(key.state != SDL_PRESSED) return; + + int moveDest = 0; + switch(key.keysym.sym) + { + case SDLK_UP: + moveDest = value - 1; + break; + case SDLK_DOWN: + moveDest = value + 1; + break; + case SDLK_PAGEUP: + moveDest = value - capacity + 1; + break; + case SDLK_PAGEDOWN: + moveDest = value + capacity - 1; + break; + case SDLK_HOME: + moveDest = 0; + break; + case SDLK_END: + moveDest = amount - capacity; + break; + default: + return; + } + + moveTo(moveDest); +} \ No newline at end of file diff --git a/client/AdventureMapButton.h b/client/AdventureMapButton.h index f9272084d..02a90b975 100644 --- a/client/AdventureMapButton.h +++ b/client/AdventureMapButton.h @@ -125,25 +125,27 @@ public: positions, //number of highest position (0 if there is only one) value; //first active element bool horizontal; + bool wheelScrolling; + bool keyScrolling; + CDefEssential *imgs ; boost::function moved; - //void(T::*moved)(int to); - //T* owner; void redrawSlider(); - void sliderClicked(); void moveLeft(); - void clickLeft(tribool down, bool previousState); - void mouseMoved (const SDL_MouseMotionEvent & sEvent); void moveRight(); void moveTo(int to); void block(bool on); void setAmount(int to); - //void activate(); // makes button active - //void deactivate(); // makes button inactive (but doesn't delete) - //void show(SDL_Surface * to); + + void keyPressed(const SDL_KeyboardEvent & key); + void wheelScrolled(bool down, bool in); + void clickLeft(tribool down, bool previousState); + void mouseMoved (const SDL_MouseMotionEvent & sEvent); + void showAll(SDL_Surface * to); + CSlider(int x, int y, int totalw, boost::function Moved, int Capacity, int Amount, int Value=0, bool Horizontal=true, int style = 0); //style 0 - brown, 1 - blue ~CSlider(); diff --git a/client/CCastleInterface.cpp b/client/CCastleInterface.cpp index 41a6e577c..dee6fb83a 100644 --- a/client/CCastleInterface.cpp +++ b/client/CCastleInterface.cpp @@ -778,7 +778,7 @@ void CCastleInterface::buildingClicked(int building) void CCastleInterface::castleTeleport(int where) { - const CGTownInstance * dest = dynamic_cast(CGI->state->map->objects[where]); + const CGTownInstance * dest = LOCPLINT->cb->getTownInfo(where, 1); LOCPLINT->cb->teleportHero(town->visitingHero, dest); close();//close this window, interface with new town will be called by town::onVisit } diff --git a/client/CHeroWindow.cpp b/client/CHeroWindow.cpp index f2ca79bf9..d8a83805d 100644 --- a/client/CHeroWindow.cpp +++ b/client/CHeroWindow.cpp @@ -418,29 +418,27 @@ void CHeroWindow::redrawCurBack() CSDL_Ext::printAtMiddle(CGI->generaltexth->jktexts[4], 262, 99, FONT_SMALL, tytulowy, curBack); //dismiss / quest log - std::vector * toPrin = CMessage::breakText(CGI->generaltexth->jktexts[8].substr(1, CGI->generaltexth->jktexts[8].size()-2)); - if(toPrin->size()==1) + std::vector toPrin = CMessage::breakText(CGI->generaltexth->jktexts[8].substr(1, CGI->generaltexth->jktexts[8].size()-2)); + if(toPrin.size()==1) { - CSDL_Ext::printAt((*toPrin)[0], 372, 439, FONT_SMALL, zwykly, curBack); + CSDL_Ext::printAt(toPrin[0], 372, 439, FONT_SMALL, zwykly, curBack); } else { - CSDL_Ext::printAt((*toPrin)[0], 372, 430, FONT_SMALL, zwykly, curBack); - CSDL_Ext::printAt((*toPrin)[1], 372, 446, FONT_SMALL, zwykly, curBack); + CSDL_Ext::printAt(toPrin[0], 372, 430, FONT_SMALL, zwykly, curBack); + CSDL_Ext::printAt(toPrin[1], 372, 446, FONT_SMALL, zwykly, curBack); } - delete toPrin; toPrin = CMessage::breakText(CGI->generaltexth->jktexts[9].substr(1, CGI->generaltexth->jktexts[9].size()-2)); - if(toPrin->size()==1) + if(toPrin.size()==1) { - CSDL_Ext::printAt((*toPrin)[0], 512, 439, FONT_SMALL, zwykly, curBack); + CSDL_Ext::printAt(toPrin[0], 512, 439, FONT_SMALL, zwykly, curBack); } else { - CSDL_Ext::printAt((*toPrin)[0], 512, 430, FONT_SMALL, zwykly, curBack); - CSDL_Ext::printAt((*toPrin)[1], 512, 446, FONT_SMALL, zwykly, curBack); + CSDL_Ext::printAt(toPrin[0], 512, 430, FONT_SMALL, zwykly, curBack); + CSDL_Ext::printAt(toPrin[1], 512, 446, FONT_SMALL, zwykly, curBack); } - delete toPrin; //printing primary skills' amounts for(int m=0; m<4; ++m) diff --git a/client/CKingdomInterface.cpp b/client/CKingdomInterface.cpp index 9bbce45da..419e5a90c 100644 --- a/client/CKingdomInterface.cpp +++ b/client/CKingdomInterface.cpp @@ -652,19 +652,17 @@ void CKingdomInterface::CTownItem::showAll(SDL_Surface * to) oss << town->dailyIncome(); CSDL_Ext::printAtMiddle(oss.str(),pos.x+189,pos.y+61,FONT_SMALL,zwykly,to); - std::vector * toPrin = CMessage::breakText(CGI->generaltexth->allTexts[265]); + std::vector toPrin = CMessage::breakText(CGI->generaltexth->allTexts[265]); - CSDL_Ext::printAt((*toPrin)[0], pos.x+4, pos.y+76, FONT_SMALL, tytulowy, to); - if(toPrin->size()!=1) - CSDL_Ext::printAt((*toPrin)[1], pos.x+4, pos.y+92, FONT_SMALL, tytulowy, to); + CSDL_Ext::printAt(toPrin[0], pos.x+4, pos.y+76, FONT_SMALL, tytulowy, to); + if(toPrin.size()!=1) + CSDL_Ext::printAt(toPrin[1], pos.x+4, pos.y+92, FONT_SMALL, tytulowy, to); - delete toPrin; toPrin = CMessage::breakText(CGI->generaltexth->allTexts[266]); - CSDL_Ext::printAt((*toPrin)[0], pos.x+351, pos.y+76, FONT_SMALL, tytulowy, to); - if(toPrin->size()!=1) - CSDL_Ext::printAt((*toPrin)[1], pos.x+351, pos.y+92, FONT_SMALL, tytulowy, to); - delete toPrin; + CSDL_Ext::printAt(toPrin[0], pos.x+351, pos.y+76, FONT_SMALL, tytulowy, to); + if(toPrin.size()!=1) + CSDL_Ext::printAt(toPrin[1], pos.x+351, pos.y+92, FONT_SMALL, tytulowy, to); for (int i=0; i * CMessage::breakText(std::string text, size_t maxLineSize, - bool userBreak, bool ifor) +std::vector CMessage::breakText( std::string text, size_t maxLineSize/*=30*/, const boost::function &charMetric /*= 0*/, bool allowLeadingWhitespace /*= false*/ ) { - std::vector * ret = new std::vector(); + std::vector ret; - boost::algorithm::trim_if(text,boost::algorithm::is_any_of(" ")); + boost::algorithm::trim_right_if(text,boost::algorithm::is_any_of(" ")); while (text.length()) { + unsigned int lineLength = 0; //in characters or given char metric + unsigned int z = 0; //our position in text + bool opened = false;//if we have an unclosed brace in current line + bool lineManuallyBroken = false; - unsigned int z = 0; - unsigned int braces = 0; - bool opened = false; - - while(z < text.length() && (text[z] != 0x0a) && (z < maxLineSize+braces)) + while(z < text.length() && text[z] != 0x0a && lineLength < maxLineSize) { /* We don't count braces in string length. */ if (text[z] == '{') - { opened=true; - braces++; - } else if (text[z]=='}') - { opened=false; - braces++; - } + else if(charMetric) + lineLength += charMetric(text[z]); + else + lineLength++; z++; } @@ -152,10 +149,13 @@ std::vector * CMessage::breakText(std::string text, size_t maxLineS int pos = z-1; // Do not break an ellipsis, backtrack until whitespace. - if (text[pos] == '.' && text[z] == '.') { + if (text[pos] == '.' && text[z] == '.') + { while (pos != 0 && text[pos] != ' ') pos--; - } else { + } + else + { /* TODO: boost should have a nice method to do that. */ while(pos > 0 && text[pos] != ' ' && @@ -172,17 +172,17 @@ std::vector * CMessage::breakText(std::string text, size_t maxLineS if(z) //non-blank line { - ret->push_back(text.substr(0, z)); + ret.push_back(text.substr(0, z)); if (opened) /* Close the brace for the current line. */ - ret->back() += '}'; + ret.back() += '}'; text.erase(0, z); } else if(text[z] == 0x0a) //blank line { - ret->push_back(""); //add empty string, no extra actions needed + ret.push_back(""); //add empty string, no extra actions needed } if (text.length() && text[0] == 0x0a) @@ -193,9 +193,12 @@ std::vector * CMessage::breakText(std::string text, size_t maxLineS /* Remove LF */ text.erase(0, 1); + + lineManuallyBroken = true; } - boost::algorithm::trim_left_if(text,boost::algorithm::is_any_of(" ")); + if(!allowLeadingWhitespace || !lineManuallyBroken) + boost::algorithm::trim_left_if(text,boost::algorithm::is_any_of(" ")); if (opened) { @@ -206,12 +209,18 @@ std::vector * CMessage::breakText(std::string text, size_t maxLineS } /* Trim whitespaces of every line. */ - for (size_t i=0; isize(); i++) - boost::algorithm::trim((*ret)[i]); + if(!allowLeadingWhitespace) + for (size_t i=0; i CMessage::breakText( std::string text, size_t maxLineWidth, EFonts font ) +{ + return breakText(text, maxLineWidth, boost::bind(&Font::getCharWidth, graphics->fonts[font], _1), true); +} + std::pair CMessage::getMaxSizes(std::vector > * txtg, int fontHeight) { std::pair ret; @@ -328,13 +337,14 @@ CSimpleWindow * CMessage::genWindow(std::string text, int player, bool centerOnM { CSimpleWindow * ret = new CSimpleWindow(); int fontHeight; - std::vector * brtext = breakText(text,32,true,true); - std::vector > * txtg = drawText(brtext, fontHeight); + std::vector brtext = breakText(text,32); + std::vector > * txtg = drawText(&brtext, fontHeight); std::pair txts = getMaxSizes(txtg, fontHeight); ret->bitmap = drawBox1(txts.first+Lmar+Rmar,txts.second+Tmar+Bmar,player); ret->pos.h = ret->bitmap->h; ret->pos.w = ret->bitmap->w; - if (centerOnMouse) { + if (centerOnMouse) + { ret->pos.x = GH.current->motion.x - ret->pos.w/2; ret->pos.y = GH.current->motion.y - ret->pos.h/2; // Put the window back on screen if necessary @@ -342,14 +352,15 @@ CSimpleWindow * CMessage::genWindow(std::string text, int player, bool centerOnM amax(ret->pos.y, 0); amin(ret->pos.x, conf.cc.resx - ret->pos.w); amin(ret->pos.y, conf.cc.resy - ret->pos.h); - } else { + } + else + { // Center on screen ret->pos.x = screen->w/2 - (ret->pos.w/2); ret->pos.y = screen->h/2 - (ret->pos.h/2); } int curh = ret->bitmap->h/2 - (fontHeight*txtg->size())/2; blitTextOnSur(txtg,fontHeight,curh,ret->bitmap); - delete brtext; delete txtg; return ret; } @@ -357,8 +368,8 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_ { int curh; int fontHeight; - std::vector * tekst = breakText(text,charperline); - std::vector > * txtg = drawText(tekst, fontHeight); + std::vector tekst = breakText(text,charperline); + std::vector > * txtg = drawText(&tekst, fontHeight); std::pair txts = getMaxSizes(txtg, fontHeight), boxs; boxs.first = std::max(txts.first,bitmap->w) // text/bitmap max width + 50; //side margins @@ -376,7 +387,6 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_ blitAt(bitmap,(ret->w/2)-(bitmap->w/2),curh,ret); curh += bitmap->h + 5; CSDL_Ext::printAtMiddle(sub,ret->w/2,curh+10,FONT_SMALL,zwykly,ret); - delete tekst; delete txtg; return ret; } @@ -384,32 +394,31 @@ SDL_Surface * CMessage::drawBoxTextBitmapSub( int player, std::string text, SDL_ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player, int charperline) { SDL_Surface * _or = NULL; - int fontHeight; - - // Try to compute a reasonable number of characters per line - if (!charperline) - { - if (text.size() < 30 && ret->buttons.size() < 2) - charperline = 30; - else if (text.size() < 200) - charperline = 40; - else if (text.size() < 750) - charperline = 50; - else - charperline = 75; //TODO: add scrollbar for very long texts - } + const Font &f = *graphics->fonts[FONT_MEDIUM]; + int fontHeight = f.height; if(dynamic_cast(ret)) //it's selection window, so we'll blit "or" between components _or = FNT_RenderText(FONT_MEDIUM,CGI->generaltexth->allTexts[4],zwykly); - std::vector * brtext = breakText(text, charperline, true, true); //text - std::vector > * txtg = drawText(brtext, fontHeight); - std::pair txts = getMaxSizes(txtg, fontHeight); + const int sizes[][2] = {{400, 100}, {500, 150}, {600, 200}}; + for(int i = 0; + i < ARRAY_COUNT(sizes) + && sizes[i][0] < conf.cc.resx - 150 + && sizes[i][1] < conf.cc.resy - 150 + && ret->text->slider; + i++) + { + ret->text->setBounds(sizes[i][0], sizes[i][1]); + } + + if(ret->text->slider) + ret->text->slider->changeUsedEvents(CIntObject::WHEEL | CIntObject::KEYBOARD, true); + + std::pair winSize(ret->text->pos.w, ret->text->pos.h); //start with text size ComponentsToBlit comps(ret->components,500,_or); - if (ret->components.size()) - txts.second += 30 + comps.h; //space to first component + winSize.second += 30 + comps.h; //space to first component int bw = 0; if (ret->buttons.size()) @@ -418,35 +427,32 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player, int bw = 20*(ret->buttons.size()-1); // space between all buttons for(size_t i=0; ibuttons.size(); i++) //and add buttons width bw+=ret->buttons[i]->imgs[0][0]->w; - txts.second += 20 + //before button + winSize.second += 20 + //before button ok->ourImages[0].bitmap->h; //button } // Clip window size - amax(txts.second, 50); - amax(txts.first, 80); - amax(txts.first, comps.w); - amax(txts.first, bw); + amax(winSize.second, 50); + amax(winSize.first, 80); + amax(winSize.first, comps.w); + amax(winSize.first, bw); - amin(txts.first, conf.cc.resx - 150); + amin(winSize.first, conf.cc.resx - 150); - ret->bitmap = drawBox1 (txts.first + 2*SIDE_MARGIN, txts.second + 2*SIDE_MARGIN, player); + ret->bitmap = drawBox1 (winSize.first + 2*SIDE_MARGIN, winSize.second + 2*SIDE_MARGIN, player); ret->pos.h=ret->bitmap->h; ret->pos.w=ret->bitmap->w; - ret->pos.x=screen->w/2-(ret->pos.w/2); - ret->pos.y=screen->h/2-(ret->pos.h/2); - if (txts.second > conf.cc.resy - 150) - { - amin(txts.second, conf.cc.resy - 150); - ret->slider = new CSlider(ret->pos.x + ret->pos.w - SIDE_MARGIN, ret->pos.y + SIDE_MARGIN, - ret->pos.h - 2*SIDE_MARGIN, boost::bind (&CInfoWindow::sliderMoved, ret, _1), brtext->size(), brtext->size(), brtext->size()-1, false, 0); - //ret->bitmap->w -= ret->slider->pos.w; //crop text so that slider has more place for itself - } - else - ret->slider = NULL; + ret->center(); + int curh = SIDE_MARGIN; - blitTextOnSur (txtg, fontHeight, curh, ret->bitmap); + + int xOffset = (ret->pos.w - ret->text->pos.w)/2; + ret->text->moveBy(Point(xOffset, SIDE_MARGIN)); + + //blitTextOnSur (txtg, fontHeight, curh, ret->bitmap); + + curh += ret->text->pos.h; if (ret->components.size()) { @@ -471,76 +477,11 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player, int ret->components[i]->pos.x += ret->pos.x; ret->components[i]->pos.y += ret->pos.y; } - delete brtext; - delete txtg; + if(_or) SDL_FreeSurface(_or); } -SDL_Surface * CMessage::genMessage -(std::string title, std::string text, EWindowType type, std::vector *addPics, void * cb) -{ -//max x 320 okolo 30 znakow - std::vector * tekst; - if (text.length() < 30) //does not need breaking - { - tekst = new std::vector(); - tekst->push_back(text); - } - else tekst = breakText(text); - int ww, hh; //dimensions of box - if (319>30+13*text.length()) - ww = 30+13*text.length(); - else ww = 319; - if (title.length()) - hh=110+(21*tekst->size()); - else hh=60+(21*tekst->size()); - if (type==yesOrNO) //make place for buttons - { - if (ww<200) ww=200; - hh+=70; - } - - SDL_Surface * ret = drawBox1(ww,hh,0); - //prepare title text - - if (title.length()) - { - SDL_Surface * titleText = FNT_RenderText(FONT_BIG,title,tytulowy); - - //draw title - SDL_Rect tytul = genRect(titleText->h,titleText->w,((ret->w/2)-(titleText->w/2)),37); - SDL_BlitSurface(titleText,NULL,ret,&tytul); - SDL_FreeSurface(titleText); - } - //draw text - for (size_t i=0; isize(); i++) - { - int by = 37+i*21; - if (title.length()) by+=40; - SDL_Surface * tresc = FNT_RenderText(FONT_BIG,(*tekst)[i],zwykly); - SDL_Rect trescRect = genRect(tresc->h,tresc->w,((ret->w/2)-(tresc->w/2)),by); - SDL_BlitSurface(tresc,NULL,ret,&trescRect); - SDL_FreeSurface(tresc); - } - if (type==yesOrNO) // add buttons - { - int by = 77+tekst->size()*21; - if (title.length()) by+=40; - int hwo = (*addPics)[0]->ourImages[0].bitmap->w, hwc=(*addPics)[0]->ourImages[0].bitmap->w; - //ok - SDL_Rect trescRect = genRect((*addPics)[0]->ourImages[0].bitmap->h,hwo,((ret->w/2)-hwo-10),by); - SDL_BlitSurface((*addPics)[0]->ourImages[0].bitmap,NULL,ret,&trescRect); - reinterpret_cast*>(cb)->push_back(trescRect); - //cancel - trescRect = genRect((*addPics)[1]->ourImages[0].bitmap->h,hwc,((ret->w/2)+10),by); - SDL_BlitSurface((*addPics)[1]->ourImages[0].bitmap,NULL,ret,&trescRect); - reinterpret_cast*>(cb)->push_back(trescRect); - } - delete tekst; - return ret; -} - void CMessage::drawBorder(int playerColor, SDL_Surface * ret, int w, int h, int x, int y) { //obwodka I-szego rzedu pozioma //border of 1st series, horizontal @@ -582,9 +523,8 @@ ComponentResolved::ComponentResolved( SComponent *Comp ) { comp = Comp; img = comp->getImg(); - std::vector * brtext = CMessage::breakText(comp->subtitle,13,true,true); //text - txt = CMessage::drawText(brtext,txtFontHeight,FONT_MEDIUM); - delete brtext; + std::vector brtext = CMessage::breakText(comp->subtitle,13); //text + txt = CMessage::drawText(&brtext,txtFontHeight,FONT_MEDIUM); //calculate dimensions std::pair textSize = CMessage::getMaxSizes(txt, txtFontHeight); diff --git a/client/CMessage.h b/client/CMessage.h index 936c959bd..db042c377 100644 --- a/client/CMessage.h +++ b/client/CMessage.h @@ -4,6 +4,7 @@ #include "FontBase.h" #include "../global.h" #include +#include /* * CMessage.h, part of VCMI engine @@ -63,12 +64,11 @@ public: static SDL_Surface * blitTextOnSur(std::vector > * txtg, int fontHeight, int & curh, SDL_Surface * ret, int xCenterPos=-1); //xPos==-1 works as if ret->w/2 static void drawIWindow(CInfoWindow * ret, std::string text, int player, int charperline); static CSimpleWindow * genWindow(std::string text, int player, bool centerOnMouse=false, int Lmar=35, int Rmar=35, int Tmar=35, int Bmar=35);//supports h3 text formatting; player sets color of window, Lmar/Rmar/Tmar/Bmar are Left/Right/Top/Bottom margins - static SDL_Surface * genMessage(std::string title, std::string text, EWindowType type=infoOnly, - std::vector *addPics=NULL, void * cb=NULL); static SDL_Surface * drawBox1(int w, int h, int playerColor=1); static void drawBorder(int playerColor, SDL_Surface * ret, int w, int h, int x=0, int y=0); static SDL_Surface * drawBoxTextBitmapSub(int player, std::string text, SDL_Surface* bitmap, std::string sub, int charperline=30, int imgToBmp=55); - static std::vector * breakText(std::string text, size_t maxLineSize=30, bool userBreak=true, bool ifor=true); + static std::vector breakText(std::string text, size_t maxLineSize=30, const boost::function &charMetric = boost::function(), bool allowLeadingWhitespace = false); + static std::vector breakText(std::string text, size_t maxLineWidth, EFonts font); static void init(); static void dispose(); }; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 960b9e5f1..47ff12b70 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -828,6 +828,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::functionchangeUsedEvents(WHEEL, true); format = CDefHandler::giveDef("SCSELC.DEF"); sortingBy = _format; @@ -1082,13 +1083,6 @@ void SelectionTab::clickLeft( tribool down, bool previousState ) select(line); } } - -void SelectionTab::wheelScrolled( bool down, bool in ) -{ - slider->moveTo(slider->value + 3 * (down ? +1 : -1)); - //select(selectionPos - slider->value + (down ? +1 : -1)); -} - void SelectionTab::keyPressed( const SDL_KeyboardEvent & key ) { if(key.state != SDL_PRESSED) return; @@ -1166,23 +1160,25 @@ InfoCard::InfoCard( CMenuScreen::EState Type ) OBJ_CONSTRUCTION; pos.x += 393; used = RCLICK; - + mapDescription = NULL; type = Type; + Rect descriptionRect(26, 149, 320, 115); + mapDescription = new CTextBox("", descriptionRect, 1); + if(type == CMenuScreen::campaignList) { - /*bg = new CPicture(BitmapHandler::loadBitmap("CamCust.bmp"), 0, 0, true); - bg->pos.x = 0; - bg->pos.y = 0;*/ + CSelectionScreen *ss = static_cast(parent); + moveChild(new CPicture(*ss->bg, descriptionRect + Point(-393, 0)), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child) } else { bg = new CPicture(BitmapHandler::loadBitmap("GSELPOP1.bmp"), 0, 0, true); + std::swap(children.front(), children.back()); pos.w = bg->pos.w; pos.h = bg->pos.h; sizes = CDefHandler::giveDef("SCNRMPSZ.DEF"); sFlags = CDefHandler::giveDef("ITGFLAGS.DEF"); - difficulty = new CHighlightableButtonsGroup(0); { static const char *difButns[] = {"GSPBUT3.DEF", "GSPBUT4.DEF", "GSPBUT5.DEF", "GSPBUT6.DEF", "GSPBUT7.DEF"}; @@ -1197,8 +1193,11 @@ InfoCard::InfoCard( CMenuScreen::EState Type ) if(type != CMenuScreen::newGame) difficulty->block(true); + + //description needs bg + moveChild(new CPicture(*bg, descriptionRect), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child) } - + } InfoCard::~InfoCard() @@ -1329,22 +1328,16 @@ void InfoCard::showAll( SDL_Surface * to ) } //blit description - std::string itemDesc, name; + std::string name; if (type == CMenuScreen::campaignList) { - itemDesc = curMap->campaignHeader->description; name = curMap->campaignHeader->name; } else { - itemDesc = curMap->mapHeader->description; name = curMap->mapHeader->name; } - std::vector *desc = CMessage::breakText(itemDesc,52); - for (int i=0;isize();i++) - printAtLoc((*desc)[i], 26, 149 + i*16, FONT_SMALL, zwykly, to); - delete desc; //name if (name.length()) @@ -1358,8 +1351,17 @@ void InfoCard::showAll( SDL_Surface * to ) void InfoCard::changeSelection( const CMapInfo *to ) { - if(to && type != CMenuScreen::newGame && type != CMenuScreen::campaignList) - difficulty->select(curOpts->difficulty, 0); + if(to && mapDescription) + { + + if (type == CMenuScreen::campaignList) + mapDescription->setTxt(to->campaignHeader->description); + else + mapDescription->setTxt(to->mapHeader->description); + + if(type != CMenuScreen::newGame && type != CMenuScreen::campaignList) + difficulty->select(curOpts->difficulty, 0); + } GH.totalRedraw(); } @@ -2219,11 +2221,11 @@ CBonusSelection::CBonusSelection( const CCampaign * _ourCampaign, int _whichMap //campaign description printAtLoc(CGI->generaltexth->allTexts[38], 481, 63, FONT_SMALL, tytulowy, background); - - std::vector *desc = CMessage::breakText(ourCampaign->header.description, 45); - for (int i=0; isize() ;i++) - printAtLoc((*desc)[i], 481, 86 + i*16, FONT_SMALL, zwykly, background); - delete desc; + +// std::vector *desc = CMessage::breakText(ourCampaign->header.description, 45); +// for (int i=0; isize() ;i++) +// printAtLoc((*desc)[i], 481, 86 + i*16, FONT_SMALL, zwykly, background); +// delete desc; //set left part of window for (int g=0; gscenarios.size(); ++g) @@ -2354,10 +2356,10 @@ void CBonusSelection::show( SDL_Surface * to ) //map description printAtLoc(CGI->generaltexth->allTexts[496], 481, 253, FONT_SMALL, tytulowy, to); - std::vector *desc = CMessage::breakText(mapDesc, 45); - for (int i=0; isize(); i++) - printAtLoc((*desc)[i], 481, 281 + i*16, FONT_SMALL, zwykly, to); - delete desc; +// std::vector *desc = CMessage::breakText(mapDesc, 45); +// for (int i=0; isize(); i++) +// printAtLoc((*desc)[i], 481, 281 + i*16, FONT_SMALL, zwykly, to); +// delete desc; //map size icon int temp; diff --git a/client/CPreGame.h b/client/CPreGame.h index b555d839d..f97230753 100644 --- a/client/CPreGame.h +++ b/client/CPreGame.h @@ -23,6 +23,7 @@ class CCampaignHeader; class CTextInput; class CCampaign; class CGStatusBar; +class CTextBox; class CMapInfo { @@ -86,6 +87,7 @@ class InfoCard : public CIntObject public: CMenuScreen::EState type; + CTextBox *mapDescription; CHighlightableButtonsGroup *difficulty; CDefHandler *sizes, *sFlags;; @@ -135,7 +137,6 @@ public: void showAll(SDL_Surface * to); void clickLeft(tribool down, bool previousState); - void wheelScrolled(bool down, bool in); void keyPressed(const SDL_KeyboardEvent & key); void onDoubleClick(); SelectionTab(CMenuScreen::EState Type, const boost::function &OnSelect, bool MultiPlayer=false); @@ -201,10 +202,10 @@ public: class CSelectionScreen : public CIntObject { +public: CPicture *bg; //general bg image InfoCard *card; OptionsTab *opt; -public: AdventureMapButton *start, *back; SelectionTab *sel; diff --git a/client/FontBase.h b/client/FontBase.h index 5e7cfdf43..32550a2cf 100644 --- a/client/FontBase.h +++ b/client/FontBase.h @@ -15,5 +15,25 @@ enum EFonts { FONT_BIG, FONT_CALLI, FONT_CREDITS, FONT_HIGH_SCORE, FONT_MEDIUM, FONT_SMALL, FONT_TIMES, FONT_TINY, FONT_VERD }; + +struct Font +{ + struct Char + { + si32 unknown1, width, unknown2, offset; + unsigned char *pixels; + }; + + Char chars[256]; + ui8 height; + + unsigned char *data; + + + Font(unsigned char *Data); + ~Font(); + int getWidth(const char *text) const; + int getCharWidth(char c) const; +}; #endif diff --git a/client/GUIBase.cpp b/client/GUIBase.cpp index 307c63941..6e95f9212 100644 --- a/client/GUIBase.cpp +++ b/client/GUIBase.cpp @@ -522,22 +522,7 @@ void CIntObject::activate() { assert(!active); active |= GENERAL; - if(used & LCLICK) - activateLClick(); - if(used & RCLICK) - activateRClick(); - if(used & HOVER) - activateHover(); - if(used & MOVE) - activateMouseMove(); - if(used & KEYBOARD) - activateKeys(); - if(used & TIME) - activateTimer(); - if(used & WHEEL) - activateWheel(); - if(used & DOUBLECLICK) - activateDClick(); + activate(used); if(defActions & ACTIVATE) for(size_t i = 0; i < children.size(); i++) @@ -545,26 +530,31 @@ void CIntObject::activate() children[i]->activate(); } +void CIntObject::activate(ui16 what) +{ + if(what & LCLICK) + activateLClick(); + if(what & RCLICK) + activateRClick(); + if(what & HOVER) + activateHover(); + if(what & MOVE) + activateMouseMove(); + if(what & KEYBOARD) + activateKeys(); + if(what & TIME) + activateTimer(); + if(what & WHEEL) + activateWheel(); + if(what & DOUBLECLICK) + activateDClick(); +} + void CIntObject::deactivate() { assert(active); active &= ~ GENERAL; - if(used & LCLICK) - deactivateLClick(); - if(used & RCLICK) - deactivateRClick(); - if(used & HOVER) - deactivateHover(); - if(used & MOVE) - deactivateMouseMove(); - if(used & KEYBOARD) - deactivateKeys(); - if(active & TIME) // TIME is special - deactivateTimer(); - if(used & WHEEL) - deactivateWheel(); - if(used & DOUBLECLICK) - deactivateDClick(); + deactivate(used); assert(!active); @@ -574,6 +564,26 @@ void CIntObject::deactivate() children[i]->deactivate(); } +void CIntObject::deactivate(ui16 what) +{ + if(what & LCLICK) + deactivateLClick(); + if(what & RCLICK) + deactivateRClick(); + if(what & HOVER) + deactivateHover(); + if(what & MOVE) + deactivateMouseMove(); + if(what & KEYBOARD) + deactivateKeys(); + if(what & TIME) // TIME is special + deactivateTimer(); + if(what & WHEEL) + deactivateWheel(); + if(what & DOUBLECLICK) + deactivateDClick(); +} + CIntObject::~CIntObject() { assert(!active); //do not delete active obj @@ -684,18 +694,19 @@ void CIntObject::onDoubleClick() { } -const Rect & CIntObject::center( const Rect &r ) +const Rect & CIntObject::center( const Rect &r, bool propagate ) { pos.w = r.w; pos.h = r.h; - pos.x = screen->w/2 - r.w/2; - pos.y = screen->h/2 - r.h/2; + moveBy(Point(screen->w/2 - r.w/2 - pos.x, + screen->h/2 - r.h/2 - pos.y), + propagate); return pos; } -const Rect & CIntObject::center() +const Rect & CIntObject::center( bool propagate ) { - return center(pos); + return center(pos, propagate); } void CIntObject::moveBy( const Point &p, bool propagate /*= true*/ ) @@ -718,8 +729,45 @@ void CIntObject::delChild(CIntObject *child) delete child; } +void CIntObject::addChild(CIntObject *child, bool adjustPosition /*= false*/) +{ + assert(!vstd::contains(children, child)); + assert(child->parent == NULL); + children.push_back(child); + child->parent = this; + if(adjustPosition) + child->pos += pos; +} + +void CIntObject::removeChild(CIntObject *child, bool adjustPosition /*= false*/) +{ + assert(vstd::contains(children, child)); + assert(child->parent == this); + children -= child; + child->parent = NULL; + if(adjustPosition) + child->pos -= pos; +} + +void CIntObject::changeUsedEvents(ui16 what, bool enable, bool adjust /*= true*/) +{ + if(enable) + { + used |= what; + if(adjust && active) + activate(what); + } + else + { + used &= ~what; + if(adjust && active) + deactivate(what); + } +} + CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free ) { + init(); bg = BG; freeSurf = Free; pos.x += x; @@ -730,6 +778,7 @@ CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free ) CPicture::CPicture( const std::string &bmpname, int x, int y ) { + init(); bg = BitmapHandler::loadBitmap(bmpname); freeSurf = true;; pos.x += x; @@ -747,24 +796,53 @@ CPicture::CPicture( const std::string &bmpname, int x, int y ) CPicture::CPicture(const Rect &r, const SDL_Color &color, bool screenFormat /*= false*/) { + init(); createSimpleRect(r, screenFormat, SDL_MapRGB(bg->format, color.r, color.g,color.b)); } CPicture::CPicture(const Rect &r, ui32 color, bool screenFormat /*= false*/) { + init(); createSimpleRect(r, screenFormat, color); } +CPicture::CPicture(SDL_Surface *BG, const Rect &SrcRect, int x /*= 0*/, int y /*= 0*/, bool free /*= false*/) +{ + srcRect = new Rect(SrcRect); + pos.x += x; + pos.y += y; + bg = BG; + freeSurf = free; +} + CPicture::~CPicture() { if(freeSurf) SDL_FreeSurface(bg); + delete srcRect; +} + +void CPicture::init() +{ + srcRect = NULL; } void CPicture::showAll( SDL_Surface * to ) { if(bg) - blitAt(bg, pos, to); + { + if(srcRect) + { + SDL_Rect srcRectCpy = *srcRect; + SDL_Rect dstRect = srcRectCpy; + dstRect.x = pos.x; + dstRect.y = pos.y; + + SDL_BlitSurface(bg, &srcRectCpy, to, &dstRect); + } + else + blitAt(bg, pos, to); + } } void CPicture::convertToScreenBPP() @@ -786,6 +864,7 @@ void CPicture::createSimpleRect(const Rect &r, bool screenFormat, ui32 color) bg = SDL_CreateRGBSurface(SDL_SWSURFACE, r.w, r.h, 8, 0, 0, 0, 0); SDL_FillRect(bg, NULL, color); + freeSurf = true; } void CPicture::colorizeAndConvert(int player) @@ -868,16 +947,10 @@ bool isArrowKey( SDLKey key ) return key >= SDLK_UP && key <= SDLK_LEFT; } -CIntObject * moveChildren(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos) +CIntObject * moveChild(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos) { - assert(vstd::contains(from->children, obj)); - assert(obj->parent == from); - from->children -= obj; - to->children.push_back(obj); - obj->parent = to; - if(adjustPos) - obj->pos -= from->pos - to->pos; - + from->removeChild(obj, adjustPos); + to->addChild(obj, adjustPos); return obj; } Rect Rect::createCentered( int w, int h ) diff --git a/client/GUIBase.h b/client/GUIBase.h index 996784414..23695a06b 100644 --- a/client/GUIBase.h +++ b/client/GUIBase.h @@ -213,7 +213,7 @@ struct Rect : public SDL_Rect } template Rect operator-(const T &t) { - return Rect(x + t.x, y + t.y, w, h); + return Rect(x - t.x, y - t.y, w, h); } Rect operator&(const Rect &p) const //rect intersection { @@ -376,6 +376,8 @@ public: void defDeactivate(); void activate(); void deactivate(); + void activate(ui16 what); + void deactivate(ui16 what); void show(SDL_Surface * to); void showAll(SDL_Surface * to); @@ -388,12 +390,26 @@ public: void blitAtLoc(SDL_Surface * src, const Point &p, SDL_Surface * dst); bool isItInLoc(const SDL_Rect &rect, int x, int y); bool isItInLoc(const SDL_Rect &rect, const Point &p); - const Rect & center(const Rect &r); //sets pos so that r will be in the center of screen, returns new position - const Rect & center(); //centers when pos.w and pos.h are set, returns new position + const Rect & center(const Rect &r, bool propagate = true); //sets pos so that r will be in the center of screen, returns new position + const Rect & center(bool propagate = true); //centers when pos.w and pos.h are set, returns new position void moveBy(const Point &p, bool propagate = true); void moveTo(const Point &p, bool propagate = true); + void changeUsedEvents(ui16 what, bool enable, bool adjust = true); - void delChild(CIntObject *child); //removes from chidlren list, deletes + void addChild(CIntObject *child, bool adjustPosition = false); + void removeChild(CIntObject *child, bool adjustPosition = false); + void delChild(CIntObject *child); //removes from children list, deletes + template void delChildNUll(T *&child, bool deactivateIfNeeded = false) //removes from children list, deletes and sets pointer to NULL + { + if(!child) + return; + + if(deactivateIfNeeded && child->active) + child->deactivate(); + + delChild(child); + child = NULL; + } }; //class for binding keys to left mouse button clicks @@ -419,29 +435,29 @@ class CSimpleWindow : public CIntObject { public: SDL_Surface * bitmap; //background - CIntObject * owner; //who made this window virtual void show(SDL_Surface * to); - CSimpleWindow():bitmap(NULL),owner(NULL){}; //c-tor + CSimpleWindow():bitmap(NULL){}; //c-tor virtual ~CSimpleWindow(); //d-tor - void activate(){}; - void deactivate(){}; }; class CPicture : public CIntObject { public: SDL_Surface *bg; - bool freeSurf; + Rect *srcRect; //if NULL then whole surface will be used + bool freeSurf; //whether surface will be freed upon CPicture destruction operator SDL_Surface*() { return bg; } - CPicture(const Rect &r, const SDL_Color &color, bool screenFormat = false); - CPicture(const Rect &r, ui32 color, bool screenFormat = false); - CPicture(SDL_Surface *BG, int x, int y, bool Free = true); + CPicture(const Rect &r, const SDL_Color &color, bool screenFormat = false); //rect filled with given color + CPicture(const Rect &r, ui32 color, bool screenFormat = false); //rect filled with given color + CPicture(SDL_Surface *BG, int x, int y, bool Free = true); //wrap existing SDL_Surface CPicture(const std::string &bmpname, int x=0, int y=0); + CPicture(SDL_Surface *BG, const Rect &SrcRext, int x = 0, int y = 0, bool free = false); //wrap subrect of given surface + void init(); void createSimpleRect(const Rect &r, bool screenFormat, ui32 color); ~CPicture(); @@ -504,7 +520,7 @@ SDLKey arrowToNum(SDLKey key); //converts arrow key to according numpad key SDLKey numToDigit(SDLKey key);//converts numpad digit key to normal digit key bool isNumKey(SDLKey key, bool number = true); //checks if key is on numpad (numbers - check only for numpad digits) bool isArrowKey(SDLKey key); -CIntObject * moveChildren(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos = false); +CIntObject * moveChild(CIntObject *obj, CIntObject *from, CIntObject *to, bool adjustPos = false); template void pushIntT() { @@ -529,5 +545,6 @@ struct SetCaptureState #define OBJ_CONSTRUCTION ObjectConstruction obj__i(this) #define OBJ_CONSTRUCTION_CAPTURING_ALL defActions = 255; SetCaptureState obj__i1(true, 255); ObjectConstruction obj__i(this) #define BLOCK_CAPTURING SetCaptureState obj__i(false, 0) +#define BLOCK_CAPTURING_DONT_TOUCH_REC_ACTIONS SetCaptureState obj__i(false, GH.defActionsDef) #endif //__GUIBASE_H__ diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 7471c183f..092ad9e44 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -612,9 +612,9 @@ void CGarrisonInt::deactivate() splitButtons[i]->deactivate(); } -CInfoWindow::CInfoWindow(std::string text, int player, int charperline, const std::vector &comps, std::vector > > &Buttons, bool delComps) +CInfoWindow::CInfoWindow(std::string Text, int player, int charperline, const std::vector &comps, std::vector > > &Buttons, bool delComps) { - slider = NULL; + OBJ_CONSTRUCTION_CAPTURING_ALL; ID = -1; this->delComps = delComps; for(int i=0;icallback.add(Buttons[i].second); //each button will close the window apart from call-defined actions } + text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, zwykly); + text->redrawParentOnScrolling = true; + buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape for(int i=0;irecActions = 0xff; + addChild(comps[i]); components.push_back(comps[i]); } - CMessage::drawIWindow(this,text,player,charperline); + CMessage::drawIWindow(this,Text,player,charperline); } + CInfoWindow::CInfoWindow() { ID = -1; delComps = false; + text = NULL; } void CInfoWindow::close() { @@ -645,54 +652,22 @@ void CInfoWindow::close() } void CInfoWindow::show(SDL_Surface * to) { - CSimpleWindow::show(to); - for(int i=0;ishow(to); - if (slider) - slider->show(to); + CIntObject::show(to); } CInfoWindow::~CInfoWindow() { - if(delComps) - { - for (int i=0;iactivate(); - for(int i=0;iactivate(); - if (slider) - slider->activate(); -} -void CInfoWindow::sliderMoved(int to) -{ - /*slider->moveTo(to); - if(!slider) return; //ignore spurious call when slider is being created - */ - redraw(); -} -void CInfoWindow::deactivate() -{ - for (int i=0;ideactivate(); - for(int i=0;ideactivate(); - if (slider) - slider->deactivate(); +// if(delComps) +// { +// for (int i=0;i *components, const CFunctionList &onYes, const CFunctionList &onNo, bool DelComps, int player) @@ -1088,7 +1063,8 @@ void CSelectableComponent::show(SDL_Surface * to) } void CSimpleWindow::show(SDL_Surface * to) { - blitAt(bitmap,pos.x,pos.y,to); + if(bitmap) + blitAt(bitmap,pos.x,pos.y,to); } CSimpleWindow::~CSimpleWindow() { @@ -1129,6 +1105,8 @@ CSelWindow::CSelWindow(const std::string &text, int player, int charperline, con for(int i=0;irecActions = 255; + addChild(comps[i]); components.push_back(comps[i]); comps[i]->onSelect = boost::bind(&CSelWindow::selectionChange,this,i); if(i<9) @@ -2932,8 +2910,11 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan if(printButtonFor(RESOURCE_RESOURCE)) new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_RESOURCE), 516, 450,"TPMRKBU5.DEF"); if(printButtonFor(CREATURE_RESOURCE)) - new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, CREATURE_RESOURCE), 516, 450,"TPMRKBU4.DEF"); - + new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, CREATURE_RESOURCE), 516, 485,"TPMRKBU4.DEF"); //was y=450, changed to not overlap res-res in some conditions + if(printButtonFor(RESOURCE_ARTIFACT)) + new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_ARTIFACT), 18, 450,"TPMRKBU2.DEF"); + if(printButtonFor(ARTIFACT_RESOURCE)) //unblock when support for art-res is ready + (new AdventureMapButton("","",boost::bind(&CMarketplaceWindow::setMode,this, RESOURCE_ARTIFACT), 18, 485,"TPMRKBU3.DEF"))->block(true); //was y=450, changed to not overlap res-res in some conditions } @@ -3212,7 +3193,7 @@ void CMarketplaceWindow::setMode(EMarketMode Mode) bool CMarketplaceWindow::printButtonFor(EMarketMode M) const { - return market->allowsTrade(M) && M != mode && (hero || mode != CREATURE_RESOURCE); + return market->allowsTrade(M) && M != mode && (hero || mode != CREATURE_RESOURCE && mode != RESOURCE_ARTIFACT && mode != ARTIFACT_RESOURCE); } void CMarketplaceWindow::garrisonChanged() @@ -5577,11 +5558,19 @@ void MoraleLuckBox::set(bool morale, const CGHeroInstance *hero) void CLabel::showAll(SDL_Surface * to) { CIntObject::showAll(to); - if(!text.length()) + std::string *hlpText = NULL; //if NULL, text field will be used + if(ignoreLeadingWhitespace) + { + hlpText = new std::string(text); + boost::trim_left(*hlpText); + } + + std::string &toPrint = hlpText ? *hlpText : text; + if(!toPrint.length()) return; static void (*printer[3])(const std::string &, int, int, EFonts, SDL_Color, SDL_Surface *, bool) = {&CSDL_Ext::printAt, &CSDL_Ext::printAtMiddle, &CSDL_Ext::printTo}; //array of printing functions - printer[alignment](text, pos.x + textOffset.x, pos.y + textOffset.y, font, color, to, false); + printer[alignment](toPrint, pos.x + textOffset.x, pos.y + textOffset.y, font, color, to, false); } CLabel::CLabel(int x, int y, EFonts Font /*= FONT_SMALL*/, EAlignment Align, const SDL_Color &Color /*= zwykly*/, const std::string &Text /*= ""*/) @@ -5606,6 +5595,88 @@ void CLabel::setTxt(const std::string &Txt) } } +CTextBox::CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font /*= FONT_SMALL*/, EAlignment Align /*= TOPLEFT*/, const SDL_Color &Color /*= zwykly*/) + :CLabel(rect.x, rect.y, Font, Align, Color, Text), slider(NULL), sliderStyle(SliderStyle) +{ + redrawParentOnScrolling = false; + autoRedraw = false; + pos.h = rect.h; + pos.w = rect.w; + assert(Align == TOPLEFT || Align == CENTER); //TODO: support for other alignments + assert(pos.w >= 80); //we need some space + setTxt(Text); +} + +void CTextBox::showAll(SDL_Surface * to) +{ + CIntObject::showAll(to); + + const Font &f = *graphics->fonts[font]; + int dy = f.height; //line height + int base_y = pos.y; + if(alignment == CENTER) + base_y += (pos.h - maxH)/2; + + int howManyLinesToPrint = slider ? slider->capacity : lines.size(); + int firstLineToPrint = slider ? slider->value : 0; + + for (int i = 0; i < howManyLinesToPrint; i++) + { + const std::string &line = lines[i + firstLineToPrint]; + int x = pos.x; + if(alignment == CENTER) + x += (pos.w - f.getWidth(line.c_str())) / 2; + + printAt(line, pos.x, base_y + i*dy, font, color, to); + } + +} + +void CTextBox::setTxt(const std::string &Txt) +{ + recalculateLines(Txt); + CLabel::setTxt(Txt); +} + +void CTextBox::sliderMoved(int to) +{ + if(redrawParentOnScrolling) + parent->redraw(); + redraw(); +} + +void CTextBox::setBounds(int limitW, int limitH) +{ + pos.h = limitH; + pos.w = limitW; + recalculateLines(text); +} + +void CTextBox::recalculateLines(const std::string &Txt) +{ + delChildNUll(slider, true); + lines.clear(); + + const Font &f = *graphics->fonts[font]; + int lineHeight = f.height; + int lineCapacity = pos.h / lineHeight; + + lines = CMessage::breakText(Txt, pos.w, font); + if(lines.size() > lineCapacity) //we need to add a slider + { + lines = CMessage::breakText(Txt, pos.w - 32 - 10, font); + OBJ_CONSTRUCTION_CAPTURING_ALL; + slider = new CSlider(pos.w - 32, 0, pos.h, boost::bind(&CTextBox::sliderMoved, this, _1), lineCapacity, lines.size(), 0, false, sliderStyle); + if(active) + slider->activate(); + } + + maxH = lineHeight * lines.size(); + maxW = 0; + BOOST_FOREACH(const std::string &line, lines) + amax(maxW, f.getWidth(line.c_str())); +} + void CGStatusBar::print(const std::string & Text) { setTxt(Text); @@ -5632,7 +5703,7 @@ CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment { init(); bg = BG; - moveChildren(bg, bg->parent, this); + moveChild(bg, bg->parent, this); pos = bg->pos; switch(Align) @@ -5782,4 +5853,4 @@ void CFocusable::moveFocus() break;; } } -} \ No newline at end of file +} diff --git a/client/GUIClasses.h b/client/GUIClasses.h index c003bfdc3..8bd991b34 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -66,23 +66,22 @@ struct SPuzzleInfo; class CGGarrison; class CStackInstance; class IMarket; +class CTextBox; extern SDL_Color tytulowy, tlo, zwykly ; class CInfoWindow : public CSimpleWindow //text + comp. + ok button { //window able to delete its components when closed public: - bool delComps; //whether comps will be deleted + CTextBox *text; std::vector buttons; + bool delComps; //whether comps will be deleted std::vector components; - CSlider *slider; + virtual void close(); void show(SDL_Surface * to); void showAll(SDL_Surface * to); - void activate(); - void sliderMoved(int to); - void deactivate(); - CInfoWindow(std::string text, int player, int charperline, const std::vector &comps, std::vector > > &Buttons, bool delComps); //c-tor + CInfoWindow(std::string Text, int player, int charperline, const std::vector &comps, std::vector > > &Buttons, bool delComps); //c-tor CInfoWindow(); //c-tor ~CInfoWindow(); //d-tor @@ -282,14 +281,39 @@ public: SDL_Color color; std::string text; CPicture *bg; - bool autoRedraw; + bool autoRedraw; //whether control will redraw itself on setTxt Point textOffset; //text will be blitted at pos + textOffset with appropriate alignment + bool ignoreLeadingWhitespace; - void setTxt(const std::string &Txt); + virtual void setTxt(const std::string &Txt); void showAll(SDL_Surface * to); //shows statusbar (with current text) CLabel(int x=0, int y=0, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly, const std::string &Text = ""); }; +//a multi-line label that tries to fit text with given available width and height; if not possible, it creates a slider for scrolling text +class CTextBox + : public CLabel +{ +public: + int maxW; //longest line of text in px + int maxH; //total height needed to print all lines + + int sliderStyle; + bool redrawParentOnScrolling; + + std::vector lines; + CSlider *slider; + + //CTextBox( std::string Text, const Point &Pos, int w, int h, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly); + CTextBox(std::string Text, const Rect &rect, int SliderStyle, EFonts Font = FONT_SMALL, EAlignment Align = TOPLEFT, const SDL_Color &Color = zwykly); + void showAll(SDL_Surface * to); //shows statusbar (with current text) + void setTxt(const std::string &Txt); + void setBounds(int limitW, int limitH); + void recalculateLines(const std::string &Txt); + + void sliderMoved(int to); +}; + class CGStatusBar : public CLabel, public IStatusBar { diff --git a/client/Graphics.cpp b/client/Graphics.cpp index d45d64980..46f6ec8eb 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -713,6 +713,13 @@ int Font::getWidth(const char *text ) const return ret; } + +int Font::getCharWidth( char c ) const +{ + const Char &C = chars[(unsigned char)c]; + return C.width + C.unknown1 + C.unknown2;; +} + /* void Font::WriteAt(const char *text, SDL_Surface *sur, int x, int y ) { diff --git a/client/Graphics.h b/client/Graphics.h index e95d13bff..aa272aaff 100644 --- a/client/Graphics.h +++ b/client/Graphics.h @@ -25,25 +25,6 @@ struct SDL_Color; struct InfoAboutHero; struct InfoAboutTown; -struct Font -{ - struct Char - { - si32 unknown1, width, unknown2, offset; - unsigned char *pixels; - }; - - Char chars[256]; - ui8 height; - - unsigned char *data; - - - Font(unsigned char *Data); - ~Font(); - int getWidth(const char *text) const; -}; - class Graphics { public: diff --git a/client/SDL_Extensions.cpp b/client/SDL_Extensions.cpp index 72348d26d..1e922be6a 100644 --- a/client/SDL_Extensions.cpp +++ b/client/SDL_Extensions.cpp @@ -80,12 +80,12 @@ void updateRect (SDL_Rect * rect, SDL_Surface * scr) void printAtMiddleWB(const std::string & text, int x, int y, TTF_Font * font, int charpr, SDL_Color kolor, SDL_Surface * dst) { - std::vector * ws = CMessage::breakText(text,charpr); + std::vector ws = CMessage::breakText(text,charpr); std::vector wesu; - wesu.resize(ws->size()); + wesu.resize(ws.size()); for (size_t i=0; i < wesu.size(); ++i) { - wesu[i]=TTF_RenderText_Blended(font,(*ws)[i].c_str(),kolor); + wesu[i]=TTF_RenderText_Blended(font,ws[i].c_str(),kolor); } int tox=0, toy=0; @@ -106,16 +106,15 @@ void printAtMiddleWB(const std::string & text, int x, int y, TTF_Font * font, in for (size_t i=0; i < wesu.size(); ++i) SDL_FreeSurface(wesu[i]); - delete ws; } void printAtWB(const std::string & text, int x, int y, TTF_Font * font, int charpr, SDL_Color kolor, SDL_Surface * dst) { - std::vector * ws = CMessage::breakText(text,charpr); + std::vector ws = CMessage::breakText(text,charpr); std::vector wesu; - wesu.resize(ws->size()); + wesu.resize(ws.size()); for (size_t i=0; i < wesu.size(); ++i) - wesu[i]=TTF_RenderText_Blended(font,(*ws)[i].c_str(),kolor); + wesu[i]=TTF_RenderText_Blended(font,ws[i].c_str(),kolor); int evy = y; for (size_t i=0; i < wesu.size(); ++i) @@ -126,7 +125,6 @@ void printAtWB(const std::string & text, int x, int y, TTF_Font * font, int char for (size_t i=0; i < wesu.size(); ++i) SDL_FreeSurface(wesu[i]); - delete ws; } void CSDL_Ext::printAtWB(const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor, SDL_Surface * dst, bool refresh) @@ -137,15 +135,14 @@ void CSDL_Ext::printAtWB(const std::string & text, int x, int y, EFonts font, in return; } const Font *f = graphics->fonts[font]; - std::vector * ws = CMessage::breakText(text,charpr); + std::vector ws = CMessage::breakText(text,charpr); int cury = y; - for (size_t i=0; i < ws->size(); ++i) + for (size_t i=0; i < ws.size(); ++i) { - printAt((*ws)[i], x, cury, font, kolor, dst, refresh); + printAt(ws[i], x, cury, font, kolor, dst, refresh); cury += f->height; } - delete ws; } @@ -158,16 +155,15 @@ void CSDL_Ext::printAtMiddleWB( const std::string & text, int x, int y, EFonts f } const Font *f = graphics->fonts[font]; - std::vector * ws = CMessage::breakText(text,charpr); - int totalHeight = ws->size() * f->height; + std::vector ws = CMessage::breakText(text,charpr); + int totalHeight = ws.size() * f->height; int cury = y - totalHeight/2; - for (size_t i=0; i < ws->size(); ++i) + for (size_t i=0; i < ws.size(); ++i) { - printAt((*ws)[i], x - f->getWidth((*ws)[i].c_str())/2, cury, font, kolor, dst, refrsh); + printAt(ws[i], x - f->getWidth(ws[i].c_str())/2, cury, font, kolor, dst, refrsh); cury += f->height; } - delete ws; } void printAtMiddle(const std::string & text, int x, int y, TTF_Font * font, SDL_Color kolor, SDL_Surface * dst, unsigned char quality=2, bool refresh=false) diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index f17554542..070490f1d 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -5459,7 +5459,7 @@ void CGPyramid::endBattle (const CGHeroInstance *h, const BattleResult *result) void CGKeys::setPropertyDer (ui8 what, ui32 val) //101-108 - enable key for player 1-8 { if (what >= 101 && what <= (100 + PLAYER_LIMIT)) - playerKeyMap.find(what-101)->second.insert(val); + playerKeyMap.find(what-101)->second.insert((ui8)val); } bool CGKeys::wasMyColorVisited (int player) const @@ -6222,6 +6222,7 @@ const IMarket * IMarket::castFrom(const CGObjectInstance *obj) { case TOWNI_TYPE: return static_cast(obj); + case 2: //Altar of Sacrifice case 7: //Black Market case 99: //Trading Post case 221: //Trading Post (snow) @@ -6282,6 +6283,9 @@ bool CGMarket::allowsTrade(EMarketMode mode) const case ARTIFACT_RESOURCE: case RESOURCE_ARTIFACT: return ID == 7; //Black Market + case ARTIFACT_EXP: + case CREATURE_EXP: + return ID == 2; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here } return false; } diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index e9142f2b0..12fd2a708 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1444,24 +1444,26 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed ) } case bartifact: { - if(!k->second.heroes.size()) - { - tlog5 << "Cannot give starting artifact - no heroes!" << std::endl; - break; - } - CArtifact *toGive; - do - { - toGive = VLC->arth->treasures[ran() % VLC->arth->treasures.size()]; - } while (!map->allowedArtifact[toGive->id]); - CGHeroInstance *hero = k->second.heroes[0]; - std::vector::iterator slot = vstd::findFirstNot(hero->artifWorn,toGive->possibleSlots); - if(slot!=toGive->possibleSlots.end()) - { - VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id, &hero->bonuses); - } - else - hero->giveArtifact(toGive->id); + //TODO: FIX IT! + +// if(!k->second.heroes.size()) +// { +// tlog5 << "Cannot give starting artifact - no heroes!" << std::endl; +// break; +// } +// CArtifact *toGive; +// do +// { +// toGive = VLC->arth->treasures[ran() % VLC->arth->treasures.size()]; +// } while (!map->allowedArtifact[toGive->id]); +// CGHeroInstance *hero = k->second.heroes[0]; +// std::vector::iterator slot = vstd::findFirstNot(hero->artifWorn,toGive->possibleSlots); +// if(slot!=toGive->possibleSlots.end()) +// { +// VLC->arth->equipArtifact(hero->artifWorn, *slot, toGive->id, &hero->bonuses); +// } +// else +// hero->giveArtifact(toGive->id); } } } diff --git a/lib/map.cpp b/lib/map.cpp index 7f16fdcf5..d6a4e439c 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -1953,7 +1953,7 @@ void Mapa::readObjects( const unsigned char * bufor, int &i) nobj->tempOwner = readNormalNr(bufor,i); i+=4; break; } - //case 2: //Altar of Sacrifice + case 2: //Altar of Sacrifice case 99: //Trading Post case 213: //Freelancer's Guild case 221: //Trading Post (snow)