From 5e762a97e284fbb2f1d35a7e7732f188c4e4d307 Mon Sep 17 00:00:00 2001 From: karwler Date: Wed, 22 Aug 2018 17:14:26 +0200 Subject: [PATCH] New shortcuts, settings and fixes --- rsc/data/languages/Deutsch.ini | 2 + rsc/data/languages/Polski.ini | 2 + ...1\201\321\201\320\272\320\270\320\271.ini" | 2 + src/engine/drawSys.cpp | 7 +- src/engine/drawSys.h | 1 + src/engine/filer.cpp | 44 ++++-- src/engine/inputSys.cpp | 5 +- src/engine/windowSys.cpp | 14 +- src/prog/defaults.h | 48 +++--- src/prog/program.cpp | 16 +- src/prog/program.h | 4 +- src/prog/progs.cpp | 60 +++++--- src/prog/progs.h | 23 +-- src/utils/layouts.cpp | 57 ++++++- src/utils/layouts.h | 21 +-- src/utils/settings.cpp | 39 ++++- src/utils/settings.h | 17 ++- src/utils/utils.cpp | 140 +++++++++--------- src/utils/utils.h | 20 ++- src/utils/vec2.h | 6 +- src/utils/widgets.cpp | 12 +- 21 files changed, 352 insertions(+), 188 deletions(-) diff --git a/rsc/data/languages/Deutsch.ini b/rsc/data/languages/Deutsch.ini index 06db53ba..5b0c7423 100644 --- a/rsc/data/languages/Deutsch.ini +++ b/rsc/data/languages/Deutsch.ini @@ -5,6 +5,8 @@ ok=ok set=einstellen up=hoch direction=Richtung +zoom=Zoom +spacing=Abstand fullscreen=Vollbild size=Größe portrait=Porträt diff --git a/rsc/data/languages/Polski.ini b/rsc/data/languages/Polski.ini index c7534bd2..6b85bb5e 100644 --- a/rsc/data/languages/Polski.ini +++ b/rsc/data/languages/Polski.ini @@ -5,6 +5,8 @@ ok=ok set=ustaw up=do góry direction=kierunek +zoom=powiększenie +spacing=odstęp fullscreen=pełny ekran size=rozmiar portrait=portret diff --git "a/rsc/data/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.ini" "b/rsc/data/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.ini" index a8243b44..3f0d6d46 100644 --- "a/rsc/data/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.ini" +++ "b/rsc/data/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.ini" @@ -5,6 +5,8 @@ ok=хорошо set=устанавливай up=вверх direction=направление +zoom=зум +spacing=пространство fullscreen=полноэкранный size=размер portrait=портрет diff --git a/src/engine/drawSys.cpp b/src/engine/drawSys.cpp index 085e4e06..d8327ab4 100644 --- a/src/engine/drawSys.cpp +++ b/src/engine/drawSys.cpp @@ -1,4 +1,9 @@ #include "world.h" +#include +#include +#include +#include +#include // FONT SET @@ -55,7 +60,7 @@ DrawSys::DrawSys(SDL_Window* window, int driverIndex) { // create and set up renderer renderer = SDL_CreateRenderer(window, driverIndex, Default::rendererFlags); if (!renderer) - throw "Couldn't create renderer:\n" + string(SDL_GetError()); + throw std::exception(string("Couldn't create renderer:\n" + string(SDL_GetError())).c_str()); SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); // load default textures with colors and initialize fonts and translations diff --git a/src/engine/drawSys.h b/src/engine/drawSys.h index af35600a..1a7ab51a 100644 --- a/src/engine/drawSys.h +++ b/src/engine/drawSys.h @@ -1,6 +1,7 @@ #pragma once #include "utils/layouts.h" +#include // loads different font sizes from one file class FontSet { diff --git a/src/engine/filer.cpp b/src/engine/filer.cpp index fdf08361..8a931baf 100644 --- a/src/engine/filer.cpp +++ b/src/engine/filer.cpp @@ -1,4 +1,9 @@ #include "world.h" +#include +#include +#include +#include +#include #include #ifdef _WIN32 #include @@ -110,8 +115,8 @@ const string Filer::dirExec = appendDsep(Filer::getExecDir()); const vector Filer::dirFonts = {Filer::dirExec, wgetenv("SystemDrive") + "\\Windows\\Fonts\\"}; const string Filer::dirSets = wgetenv("AppData") + "\\" + Default::titleDefault + "\\"; #else -const vector Filer::dirFonts = {Filer::dirExec, "/usr/share/fonts/", string(getenv("HOME")) + "/.fonts/"}; -const string Filer::dirSets = string(getenv("HOME")) + "/." + Default::titleExtra + "/"; +const vector Filer::dirFonts = {Filer::dirExec, "/usr/share/fonts/", string(std::getenv("HOME")) + "/.fonts/"}; +const string Filer::dirSets = string(std::getenv("HOME")) + "/." + Default::titleExtra + "/"; #endif const string Filer::dirLangs = Filer::dirExec + Default::dirLanguages + dsep; const string Filer::dirTexs = Filer::dirExec + Default::dirTextures + dsep; @@ -237,7 +242,11 @@ Settings Filer::getSettings() { else if (il.getArg() == Default::iniKeywordResolution) sets.setResolution(il.getVal()); else if (il.getArg() == Default::iniKeywordDirection) - sets.direction = strToEnum(Default::directionNames, il.getVal()); + sets.direction.set(il.getVal()); + else if (il.getArg() == Default::iniKeywordZoom) + sets.zoom = stof(il.getVal()); + else if (il.getArg() == Default::iniKeywordSpacing) + sets.spacing = stoi(il.getVal()); else if (il.getArg() == Default::iniKeywordFont) sets.setFont(il.getVal()); else if (il.getArg() == Default::iniKeywordLanguage) @@ -261,7 +270,9 @@ void Filer::saveSettings(const Settings& sets) { IniLine::line(Default::iniKeywordMaximized, btos(sets.maximized)), IniLine::line(Default::iniKeywordFullscreen, btos(sets.fullscreen)), IniLine::line(Default::iniKeywordResolution, sets.getResolutionString()), - IniLine::line(Default::iniKeywordDirection, enumToStr(Default::directionNames, sets.direction)), + IniLine::line(Default::iniKeywordDirection, sets.direction.toString()), + IniLine::line(Default::iniKeywordZoom, ntos(sets.zoom)), + IniLine::line(Default::iniKeywordSpacing, ntos(sets.spacing)), IniLine::line(Default::iniKeywordFont, sets.getFont()), IniLine::line(Default::iniKeywordLanguage, sets.getLang()), IniLine::line(Default::iniKeywordTheme, sets.getTheme()), @@ -284,10 +295,13 @@ vector Filer::getBindings() { for (string& line : lines) { IniLine il(line); - if (il.getType() != IniLine::Type::argKeyVal || il.getVal().size() < 3) + if (il.getType() != IniLine::Type::argVal || il.getVal().length() < 3) continue; sizt bid = strToEnum(Default::bindingNames, il.getArg()); + if (bid >= bindings.size()) + continue; + switch (toupper(il.getVal()[0])) { case 'K': // keyboard key bindings[bid].setKey(SDL_GetScancodeFromName(il.getVal().substr(2).c_str())); @@ -296,7 +310,7 @@ vector Filer::getBindings() { bindings[bid].setJbutton(stoi(il.getVal().substr(2))); break; case 'H': // joystick hat - for (sizt i = 2; i < il.getVal().size(); i++) + for (sizt i = 2; i < il.getVal().length(); i++) if (il.getVal()[i] < '0' || il.getVal()[i] > '9') { bindings[bid].setJhat(stoi(il.getVal().substr(2, i-2)), jtStrToHat(il.getVal().substr(i+1))); break; @@ -305,12 +319,16 @@ vector Filer::getBindings() { case 'A': // joystick axis bindings[bid].setJaxis(stoi(il.getVal().substr(3)), (il.getVal()[2] != '-')); break; - case 'G': // gamepad button - bindings[bid].setGbutton(strToEnum(Default::gbuttonNames, il.getVal().substr(2))); - break; - case 'X': // gamepad axis - bindings[bid].setGaxis(strToEnum(Default::gaxisNames, il.getVal().substr(3)), (il.getVal()[2] != '-')); - } + case 'G': { // gamepad button + SDL_GameControllerButton cid = strToEnum(Default::gbuttonNames, il.getVal().substr(2)); + if (cid < SDL_CONTROLLER_BUTTON_MAX) + bindings[bid].setGbutton(cid); + break; } + case 'X': { // gamepad axis + SDL_GameControllerAxis cid = strToEnum(Default::gaxisNames, il.getVal().substr(3)); + if (cid < SDL_CONTROLLER_AXIS_MAX) + bindings[bid].setGaxis(cid, (il.getVal()[2] != '-')); + } } } return bindings; } @@ -607,7 +625,7 @@ string Filer::findFont(const string& font) { for (const string& drc : dirFonts) // check font directories for (string& it : listDirRecursively(drc)) - if (!strcicmp(hasExt(it) ? delExt(filename(it)).c_str() : filename(it).c_str(), font.c_str()) && isFont(it)) + if (!strcicmp(hasExt(it) ? delExt(filename(it)) : filename(it), font) && isFont(it)) return it; return ""; // nothing found } diff --git a/src/engine/inputSys.cpp b/src/engine/inputSys.cpp index 914247ab..d4f110ef 100644 --- a/src/engine/inputSys.cpp +++ b/src/engine/inputSys.cpp @@ -154,8 +154,7 @@ void InputSys::checkBindingsX(SDL_GameControllerAxis gaxis, bool positive) { } bool InputSys::isPressed(Binding::Type type, float& amt) const { - sizt i = static_cast(type); - return bindings[i].isAxis() ? isPressed(bindings[i], amt) : false; + return bindings[static_cast(type)].isAxis() ? isPressed(bindings[static_cast(type)], amt) : false; } bool InputSys::isPressed(const Binding& abind, float& amt) const { @@ -260,7 +259,7 @@ void InputSys::removeController(int id) { } int InputSys::checkAxisValue(int value) const { - return abs(value) > World::winSys()->sets.getDeadzone() ? value : 0; + return std::abs(value) > World::winSys()->sets.getDeadzone() ? value : 0; } float InputSys::axisToFloat(int axisValue) { diff --git a/src/engine/windowSys.cpp b/src/engine/windowSys.cpp index 3a490c78..46ae4d5b 100644 --- a/src/engine/windowSys.cpp +++ b/src/engine/windowSys.cpp @@ -1,4 +1,6 @@ #include "world.h" +#include +#include WindowSys::WindowSys() : run(true), @@ -10,8 +12,8 @@ int WindowSys::start() { try { init(); exec(); - } catch (const string& str) { - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", str.c_str(), window); + } catch (const std::exception& e) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", e.what(), window); } catch (...) { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Unknown error.", window); } @@ -21,9 +23,9 @@ int WindowSys::start() { void WindowSys::init() { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER)) - throw "Couldn't initialize SDL:\n" + string(SDL_GetError()); + throw std::exception(string("Couldn't initialize SDL:\n" + string(SDL_GetError())).c_str()); if (TTF_Init()) - throw "Couldn't initialize fonts:\n" + string(SDL_GetError()); + throw std::exception(string("Couldn't initialize fonts:\n" + string(SDL_GetError())).c_str()); int flags = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF | IMG_INIT_WEBP); if (!(flags & IMG_INIT_JPG)) @@ -53,7 +55,7 @@ void WindowSys::init() { inputSys.reset(new InputSys); scene.reset(new Scene); program.reset(new Program); - program->init(); + program->start(); } void WindowSys::exec() { @@ -104,7 +106,7 @@ void WindowSys::createWindow() { window = SDL_CreateWindow(Default::titleDefault, Default::windowPos.x, Default::windowPos.y, sets.resolution.x, sets.resolution.y, flags); if (!window) - throw "Couldn't create window:\n" + string(SDL_GetError()); + throw std::exception(string("Couldn't create window:\n" + string(SDL_GetError())).c_str()); // minor stuff SDL_Surface* icon = IMG_Load(string(Filer::dirExec + Default::fileIcon).c_str()); diff --git a/src/prog/defaults.h b/src/prog/defaults.h index 73a7588e..5784d051 100644 --- a/src/prog/defaults.h +++ b/src/prog/defaults.h @@ -1,16 +1,8 @@ #pragma once // stuff that's used pretty much everywhere -#include -#include -#include -#include -#include #include "utils/vec2.h" - -#include -#include -#include +#include #include #include #include @@ -73,6 +65,7 @@ class Layout; class Program; class ProgState; +// events using PCall = void (Program::*)(Button*); using SBCall = void (ProgState::*)(); using SACall = void (ProgState::*)(float); @@ -92,6 +85,8 @@ namespace Default { const char language[] = "English"; const bool maximized = false; const bool fullscreen = false; +const float zoom = 1.f; +const int spacing = 10; const vec2i resolution(800, 600); const char font[] = "Arial"; const vec2f scrollSpeed(800.f, 1000.f); @@ -125,14 +120,17 @@ const SDL_Scancode keyRight = SDL_SCANCODE_RIGHT; const SDL_Scancode keyCenterView = SDL_SCANCODE_C; const SDL_Scancode keyScrollFast = SDL_SCANCODE_X; const SDL_Scancode keyScrollSlow = SDL_SCANCODE_Z; -const SDL_Scancode keyPageUp = SDL_SCANCODE_W; -const SDL_Scancode keyPageDown = SDL_SCANCODE_S; -const SDL_Scancode keyZoomIn = SDL_SCANCODE_D; -const SDL_Scancode keyZoomOut = SDL_SCANCODE_A; +const SDL_Scancode keyNextPage = SDL_SCANCODE_PAGEDOWN; +const SDL_Scancode keyPrevPage = SDL_SCANCODE_PAGEUP; +const SDL_Scancode keyZoomIn = SDL_SCANCODE_W; +const SDL_Scancode keyZoomOut = SDL_SCANCODE_S; const SDL_Scancode keyZoomReset = SDL_SCANCODE_R; -const SDL_Scancode keyNextDir = SDL_SCANCODE_E; -const SDL_Scancode keyPrevDir = SDL_SCANCODE_Q; -const SDL_Scancode keyFullscreen = SDL_SCANCODE_F; +const SDL_Scancode keyToStart = SDL_SCANCODE_HOME; +const SDL_Scancode keyToEnd = SDL_SCANCODE_END; +const SDL_Scancode keyNextDir = SDL_SCANCODE_N; +const SDL_Scancode keyPrevDir = SDL_SCANCODE_B; +const SDL_Scancode keyFullscreen = SDL_SCANCODE_F11; +const SDL_Scancode keyRefresh = SDL_SCANCODE_F5; // joystick bindings const uint8 jbuttonEnter = 2; @@ -184,7 +182,7 @@ const bool axisDirRight = true; const bool axisDirLeft = false; // widgets' properties -const int spacing = 5; +const int itemSpacing = 5; const int itemHeight = 30; const int sbarSize = 10; const int checkboxSpacing = 5; @@ -212,6 +210,8 @@ const char iniKeywordMaximized[] = "maximized"; const char iniKeywordFullscreen[] = "fullscreen"; const char iniKeywordResolution[] = "resolution"; const char iniKeywordDirection[] = "direction"; +const char iniKeywordZoom[] = "zoom"; +const char iniKeywordSpacing[] = "spacing"; const char iniKeywordFont[] = "font"; const char iniKeywordLanguage[] = "language"; const char iniKeywordTheme[] = "theme"; @@ -239,15 +239,19 @@ const vector bindingNames = { "center view", "scroll fast", "scroll slow", - "page up", - "page down", + "next page", + "prev page", "zoom in", "zoom out", "zoom reset", + "to start", + "to end", "next directory", "prev directory", - "fullscreen" + "fullscreen", + "refresh" }; + const map hatNames = { pair(SDL_HAT_CENTERED, "Center"), pair(SDL_HAT_UP, "Up"), @@ -259,6 +263,7 @@ const map hatNames = { pair(SDL_HAT_LEFTDOWN, "Left-Down"), pair(SDL_HAT_LEFTUP, "Left-Up") }; + const vector gbuttonNames = { "A", "B", @@ -276,6 +281,7 @@ const vector gbuttonNames = { "Left", "Right" }; + const vector gaxisNames = { "LX", "LY", @@ -284,6 +290,7 @@ const vector gaxisNames = { "LT", "RT" }; + const vector colorNames = { "background", "normal", @@ -293,6 +300,7 @@ const vector colorNames = { "text", "texture" }; + const vector directionNames = { "Up", "Down", diff --git a/src/prog/program.cpp b/src/prog/program.cpp index 4d8d7b11..71f0c272 100644 --- a/src/prog/program.cpp +++ b/src/prog/program.cpp @@ -6,7 +6,7 @@ Program::Program() : state(new ProgState) // necessary as a placeholder to prevent nullptr exceptions {} -void Program::init() { +void Program::start() { if (!(World::getArgs().size() && openFile(World::getArg(0)))) eventOpenBookList(); } @@ -38,7 +38,7 @@ void Program::eventOpenLastPage(Button* but) { bool Program::openFile(string file) { file = absolutePath(file); - if (Filer::isPicture(file)) { + if (Filer::isPicture(file) || Filer::isArchive(file)) { browser.reset(new Browser(dseps, parentPath(file), &Program::eventOpenBookList)); if (startReader(filename(file))) return true; @@ -120,7 +120,15 @@ void Program::eventOpenSettings(Button* but) { } void Program::eventSwitchDirection(Button* but) { - World::winSys()->sets.direction = strToEnum(Default::directionNames, static_cast(but)->getText()); + World::winSys()->sets.direction.set(static_cast(but)->getText()); +} + +void Program::eventSetZoom(Button * but) { + World::winSys()->sets.zoom = stof(static_cast(but)->getText()); +} + +void Program::eventSetSpacing(Button* but) { + World::winSys()->sets.spacing = stoi(static_cast(but)->getText()); } void Program::eventSwitchLanguage(Button* but) { @@ -149,7 +157,7 @@ void Program::eventOpenLibDirBrowser(Button* but) { #ifdef _WIN32 browser.reset(new Browser("\\", Filer::wgetenv("UserProfile"), &Program::eventOpenSettings)); #else - browser.reset(new Browser("/", getenv("HOME"), &Program::eventOpenSettings)); + browser.reset(new Browser("/", std::getenv("HOME"), &Program::eventOpenSettings)); #endif setState(new ProgSearchDir); } diff --git a/src/prog/program.h b/src/prog/program.h index 8908d84f..bd32557e 100644 --- a/src/prog/program.h +++ b/src/prog/program.h @@ -8,7 +8,7 @@ class Program { public: Program(); - void init(); + void start(); // books void eventOpenBookList(Button* but=nullptr); @@ -34,6 +34,8 @@ class Program { // settings void eventOpenSettings(Button* but=nullptr); void eventSwitchDirection(Button* but); + void eventSetZoom(Button* but); + void eventSetSpacing(Button* but); void eventSwitchLanguage(Button* but); void eventSetLibraryDirLE(Button* but); void eventSetLibraryDirBW(Button* but); diff --git a/src/prog/progs.cpp b/src/prog/progs.cpp index b9ceffba..33e48dc7 100644 --- a/src/prog/progs.cpp +++ b/src/prog/progs.cpp @@ -84,6 +84,10 @@ void ProgState::eventFullscreen() { World::winSys()->setFullscreen(!World::winSys()->sets.fullscreen); } +void ProgState::eventRefresh() { + World::scene()->resetLayouts(); +} + Popup* ProgState::createPopupMessage(const string& msg, const vec2& size) { vector bot = { new Widget(1.f), @@ -211,16 +215,12 @@ void ProgReader::eventScrollLeft(float amt) { World::scene()->getLayout()->onScroll(vec2i(-modifySpeed(amt * World::winSys()->sets.scrollSpeed.x), 0)); } -void ProgReader::eventPageUp() { - ReaderBox* reader = static_cast(World::scene()->getLayout()); - sizt i = reader->visibleWidgets().l; - reader->scrollToWidgetPos(i == 0 ? i : i-1); +void ProgReader::eventNextPage() { + static_cast(World::scene()->getLayout())->scrollToNext(); } -void ProgReader::eventPageDown() { - ReaderBox* reader = static_cast(World::scene()->getLayout()); - sizt i = reader->visibleWidgets().u; - reader->scrollToWidgetPos(i == reader->getWidgets().size() ? i-1 : i); +void ProgReader::eventPrevPage() { + static_cast(World::scene()->getLayout())->scrollToPrevious(); } void ProgReader::eventZoomIn() { @@ -235,6 +235,14 @@ void ProgReader::eventZoomReset() { World::program()->eventZoomReset(); } +void ProgReader::eventToStart() { + static_cast(World::scene()->getLayout())->scrollToLimit(true); +} + +void ProgReader::eventToEnd() { + static_cast(World::scene()->getLayout())->scrollToLimit(false); +} + void ProgReader::eventCenterView() { World::program()->eventCenterView(); } @@ -250,16 +258,12 @@ void ProgReader::eventPrevDir() { void ProgReader::eventClosing() { if (World::program()->getBrowser()->getCurType() == Browser::FileType::archive) Filer::saveLastPage(World::program()->getBrowser()->curFilepath()); - else { - ReaderBox* reader = static_cast(World::scene()->getLayout()); - vec2t vis = reader->visibleWidgets(); - if (vis.l < vis.u) - Filer::saveLastPage(childPath(World::program()->getBrowser()->getCurDir(), reader->getFile(vis.l))); - } + else + static_cast(World::scene()->getLayout())->saveCurPage(); } Layout* ProgReader::createLayout() { - return new ReaderBox(1.f, World::winSys()->sets.direction); + return new ReaderBox(1.f, World::winSys()->sets.direction, World::winSys()->sets.zoom, World::winSys()->sets.spacing); } Overlay* ProgReader::createOverlay() { @@ -323,6 +327,8 @@ Layout* ProgSettings::createLayout() { }; vector txs = { World::drawSys()->translation("direction"), + World::drawSys()->translation("zoom"), + World::drawSys()->translation("spacing"), World::drawSys()->translation("fullscreen"), World::drawSys()->translation("size"), World::drawSys()->translation("theme"), @@ -345,37 +351,43 @@ Layout* ProgSettings::createLayout() { Text dznum(ntos(Default::axisLimit), lineHeight); vector lx[] = { { new Label(descLength, txs[0]), - new SwitchBox(1.f, Default::directionNames, enumToStr(Default::directionNames, World::winSys()->sets.direction), &Program::eventSwitchDirection) + new SwitchBox(1.f, Default::directionNames, World::winSys()->sets.direction.toString(), &Program::eventSwitchDirection) },{ new Label(descLength, txs[1]), + new LineEdit(1.f, ntos(World::winSys()->sets.zoom), &Program::eventSetZoom, nullptr, nullptr, LineEdit::TextType::uFloating) + }, { + new Label(descLength, txs[2]), + new LineEdit(1.f, ntos(World::winSys()->sets.spacing), &Program::eventSetSpacing, nullptr, nullptr, LineEdit::TextType::uInteger) + }, { + new Label(descLength, txs[3]), new CheckBox(lineHeight, World::winSys()->sets.fullscreen, &Program::eventSwitchFullscreen) },{ - new Label(descLength, txs[2]), + new Label(descLength, txs[4]), new Label(butts[0].length, butts[0].text, &Program::eventSetPortrait), new Label(butts[1].length, butts[1].text, &Program::eventSetLandscape), new Label(butts[2].length, butts[2].text, &Program::eventSetSquare), new Label(butts[3].length, butts[3].text, &Program::eventSetFill) }, { - new Label(descLength, txs[3]), + new Label(descLength, txs[5]), new SwitchBox(1.f, Filer::getAvailibleThemes(), World::winSys()->sets.getTheme(), &Program::eventSetTheme) }, { - new Label(descLength, txs[4]), + new Label(descLength, txs[6]), new SwitchBox(1.f, Filer::getAvailibleLanguages(), World::winSys()->sets.getLang(), &Program::eventSwitchLanguage) }, { - new Label(descLength, txs[5]), + new Label(descLength, txs[7]), new LineEdit(1.f, World::winSys()->sets.getFont(), &Program::eventSetFont) }, { - new Label(descLength, txs[6]), + new Label(descLength, txs[8]), new LineEdit(1.f, World::winSys()->sets.getDirLib(), &Program::eventSetLibraryDirLE), new Label(dots.length, dots.text, &Program::eventOpenLibDirBrowser, nullptr, nullptr, Label::Alignment::center) }, { - new Label(descLength, txs[7]), + new Label(descLength, txs[9]), new SwitchBox(1.f, Settings::getAvailibleRenderers(), World::winSys()->sets.renderer, &Program::eventSetRenderer) }, { - new Label(descLength, txs[8]), + new Label(descLength, txs[10]), new LineEdit(1.f, World::winSys()->sets.getScrollSpeedString(), &Program::eventSetScrollSpeed, nullptr, nullptr, LineEdit::TextType::sFloatingSpaced) }, { - new Label(descLength, txs[9]), + new Label(descLength, txs[11]), new Slider(1.f, World::winSys()->sets.getDeadzone(), 0, Default::axisLimit, &Program::eventSetDeadzoneSL), new LineEdit(dznum.length, ntos(World::winSys()->sets.getDeadzone()), &Program::eventSetDeadzoneLE, nullptr, nullptr, LineEdit::TextType::uInteger) } }; diff --git a/src/prog/progs.h b/src/prog/progs.h index 97e4d5f0..77ca9f8f 100644 --- a/src/prog/progs.h +++ b/src/prog/progs.h @@ -5,7 +5,7 @@ // for handling program state specific things that occur in all states class ProgState { public: - virtual void eventEnter(); + void eventEnter(); virtual void eventEscape() {} virtual void eventUp(); virtual void eventDown(); @@ -15,19 +15,22 @@ class ProgState { virtual void eventScrollDown(float amt) {} virtual void eventScrollLeft(float amt) {} virtual void eventScrollRight(float amt) {} - virtual void eventCursorUp(float amt); - virtual void eventCursorDown(float amt); - virtual void eventCursorLeft(float amt); - virtual void eventCursorRight(float amt); + void eventCursorUp(float amt); + void eventCursorDown(float amt); + void eventCursorLeft(float amt); + void eventCursorRight(float amt); virtual void eventCenterView() {} - virtual void eventPageUp() {} - virtual void eventPageDown() {} + virtual void eventNextPage() {} + virtual void eventPrevPage() {} virtual void eventZoomIn() {} virtual void eventZoomOut() {} virtual void eventZoomReset() {} + virtual void eventToStart() {} + virtual void eventToEnd() {} virtual void eventNextDir() {} virtual void eventPrevDir() {} virtual void eventFullscreen(); + void eventRefresh(); virtual void eventFileDrop(char* file) {} virtual void eventClosing() {} @@ -87,11 +90,13 @@ class ProgReader : public ProgState { virtual void eventScrollLeft(float amt) override; virtual void eventScrollRight(float amt) override; virtual void eventCenterView() override; - virtual void eventPageUp() override; - virtual void eventPageDown() override; + virtual void eventNextPage() override; + virtual void eventPrevPage() override; virtual void eventZoomIn() override; virtual void eventZoomOut() override; virtual void eventZoomReset() override; + virtual void eventToStart() override; + virtual void eventToEnd() override; virtual void eventNextDir() override; virtual void eventPrevDir() override; diff --git a/src/utils/layouts.cpp b/src/utils/layouts.cpp index 34b3b770..3ce7b942 100644 --- a/src/utils/layouts.cpp +++ b/src/utils/layouts.cpp @@ -325,12 +325,49 @@ void ScrollArea::scrollToSelected() { } void ScrollArea::scrollToWidgetPos(sizt id) { - listPos[direction.vertical()] = wgtRPos(id); + int8 di = direction.vertical(); + listPos[di] = bringUnder(wgtRPos(id), listLim()[di]); } void ScrollArea::scrollToWidgetEnd(sizt id) { int8 di = direction.vertical(); - listPos[di] = wgtREnd(id) - size()[di]; + listPos[di] = bringOver(wgtREnd(id) - size()[di], 0); +} + +void ScrollArea::scrollToNext() { + scrollToFollowing(direction.positive() ? visibleWidgets().l + 1 : visibleWidgets().u - 2, false); +} + +void ScrollArea::scrollToPrevious() { + int8 dv = direction.vertical(); + sizt id; + if (direction.positive()) { + id = visibleWidgets().l; + if (listPos[dv] <= wgtRPos(id)) + id--; + } else { + id = visibleWidgets().u - 1; + if (listPos[dv] + size()[dv] >= wgtREnd(id)) + id++; + } + scrollToFollowing(id, true); +} + +void ScrollArea::scrollToLimit(bool start) { + int8 di = direction.vertical(); + listPos[di] = direction.positive() == start ? 0 : listLim()[di]; + motion = 0.f; +} + +void ScrollArea::scrollToFollowing(sizt id, bool prev) { + if (id < widgets.size()) { + if (direction.positive()) + scrollToWidgetPos(id); + else + scrollToWidgetEnd(id); + } else + scrollToLimit(prev); + motion = 0.f; } void ScrollArea::setSlider(int spos) { @@ -522,11 +559,11 @@ int TileBox::wgtREnd(sizt id) const { // READER BOX -ReaderBox::ReaderBox(const Size& relSize, const Direction& direction, int spacing, Layout* parent, sizt id) : +ReaderBox::ReaderBox(const Size& relSize, const Direction& direction, float zoom, int spacing, Layout* parent, sizt id) : ScrollArea(relSize, {}, direction, Select::none, spacing, parent, id), + zoom(zoom), countDown(true), - cursorTimer(Default::menuHideTimeout), - zoom(1.f) + cursorTimer(Default::menuHideTimeout) { pics = World::program()->getBrowser()->getCurType() == Browser::FileType::archive ? World::drawSys()->loadTexturesArchive(World::program()->getBrowser()->curFilepath()) : World::drawSys()->loadTexturesDirectory(World::program()->getBrowser()->getCurDir()); widgets.resize(pics.size()); @@ -591,7 +628,10 @@ void ReaderBox::postInit() { if (World::program()->getBrowser()->getCurType() == Browser::FileType::picture) for (sizt i = 0; i < widgets.size(); i++) if (pics[i].first == World::program()->getBrowser()->getCurFile()) { - scrollToWidgetPos(i); + if (direction.positive()) + scrollToWidgetPos(i); + else + scrollToWidgetEnd(i); break; } centerList(); @@ -623,6 +663,11 @@ void ReaderBox::centerList() { listPos[di] = listLim()[di] / 2; } +void ReaderBox::saveCurPage() { + if (widgets.size()) + Filer::saveLastPage(childPath(World::program()->getBrowser()->getCurDir(), pics[direction.positive() ? visibleWidgets().l : visibleWidgets().u - 1].first)); +} + vec2i ReaderBox::wgtPosition(sizt id) const { return position() + positions[id] + vec2i(0, id * spacing, direction.horizontal()) - listPos; } diff --git a/src/utils/layouts.h b/src/utils/layouts.h index 4945df41..4caf01e6 100644 --- a/src/utils/layouts.h +++ b/src/utils/layouts.h @@ -11,7 +11,7 @@ class Layout : public Widget { any }; - Layout(const Size& relSize=Size(), const vector& children={}, const Direction& direction=Direction::down, Select select=Select::none, int spacing=Default::spacing, Layout* parent=nullptr, sizt id=SIZE_MAX); + Layout(const Size& relSize=Size(), const vector& children={}, const Direction& direction=Direction::down, Select select=Select::none, int spacing=Default::itemSpacing, Layout* parent=nullptr, sizt id=SIZE_MAX); virtual ~Layout(); virtual void drawSelf() override; @@ -27,7 +27,6 @@ class Layout : public Widget { Widget* getWidget(sizt id) const { return widgets[id]; } const vector& getWidgets() const { return widgets; } - const Direction& getDirection() const { return direction; } const uset getSelected() const { return selected; } virtual vec2i position() const override; virtual vec2i size() const override; @@ -58,7 +57,7 @@ class Layout : public Widget { // layout with background with free position/size (shouldn't have a parent) class Popup : public Layout { public: - Popup(const vec2s& relSize=vec2s(), const vector& children={}, const Direction& direction=Direction::down, int spacing=Default::spacing); + Popup(const vec2s& relSize=vec2s(), const vector& children={}, const Direction& direction=Direction::down, int spacing=Default::itemSpacing); virtual ~Popup() {} virtual void drawSelf() override; @@ -74,7 +73,7 @@ class Popup : public Layout { // popup that can be enabled or disabled class Overlay : public Popup { public: - Overlay(const vec2s& position=vec2s(), const vec2s& relSize=vec2s(), const vec2s& activationPos=vec2s(), const vec2s& activationSize=vec2s(), const vector& children={}, const Direction& direction=Direction::down, int spacing=Default::spacing); + Overlay(const vec2s& position=vec2s(), const vec2s& relSize=vec2s(), const vec2s& activationPos=vec2s(), const vec2s& activationSize=vec2s(), const vector& children={}, const Direction& direction=Direction::down, int spacing=Default::itemSpacing); virtual ~Overlay() {} virtual vec2i position() const override; @@ -89,7 +88,7 @@ class Overlay : public Popup { // places widgets vertically through which the user can scroll (DON"T PUT SCROLL AREAS INTO OTHER SCROLL AREAS) class ScrollArea : public Layout { public: - ScrollArea(const Size& relSize=Size(), const vector& children={}, const Direction& direction=Direction::down, Select select=Select::none, int spacing=Default::spacing, Layout* parent=nullptr, sizt id=SIZE_MAX); + ScrollArea(const Size& relSize=Size(), const vector& children={}, const Direction& direction=Direction::down, Select select=Select::none, int spacing=Default::itemSpacing, Layout* parent=nullptr, sizt id=SIZE_MAX); virtual ~ScrollArea() {} virtual void drawSelf() override; @@ -104,6 +103,9 @@ class ScrollArea : public Layout { virtual void navSelectFrom(int mid, const Direction& dir) override; void scrollToWidgetPos(sizt id); // set listPos.y to the widget's position void scrollToWidgetEnd(sizt id); + void scrollToNext(); // scroll to next widget + void scrollToPrevious(); // scroll to previous widget + void scrollToLimit(bool start); // scroll to start or end of the list relative to it's direction virtual SDL_Rect frame() const; virtual vec2i wgtPosition(sizt id) const; @@ -125,18 +127,19 @@ class ScrollArea : public Layout { vec2f motion; // how much the list scrolls over time int diffSliderMouse; // space between slider and mouse position + void scrollToFollowing(sizt id, bool prev); void setSlider(int ypos); int barSize() const; // returns 0 if slider isn't needed int sliderSize() const; int sliderPos() const; int sliderLim() const; // max slider position - void throttleMotion(float& mov, float dSec); + static void throttleMotion(float& mov, float dSec); }; // places items as tiles one after another class TileBox : public ScrollArea { public: - TileBox(const Size& relSize=Size(), const vector& children={}, int childHeight=Default::itemHeight, const Direction& direction=Direction::down, Select select=Select::none, int spacing=Default::spacing, Layout* parent=nullptr, sizt id=SIZE_MAX); + TileBox(const Size& relSize=Size(), const vector& children={}, int childHeight=Default::itemHeight, const Direction& direction=Direction::down, Select select=Select::none, int spacing=Default::itemSpacing, Layout* parent=nullptr, sizt id=SIZE_MAX); virtual ~TileBox() {} virtual void onResize() override; @@ -161,7 +164,7 @@ class TileBox : public ScrollArea { // for scrolling through pictures class ReaderBox : public ScrollArea { public: - ReaderBox(const Size& relSize=Size(), const Direction& direction=Direction::down, int spacing=Default::spacing, Layout* parent=nullptr, sizt id=SIZE_MAX); + ReaderBox(const Size& relSize=Size(), const Direction& direction=Direction::down, float zoom=Default::zoom, int spacing=Default::spacing, Layout* parent=nullptr, sizt id=SIZE_MAX); virtual ~ReaderBox(); virtual void drawSelf() override; @@ -174,7 +177,7 @@ class ReaderBox : public ScrollArea { float getZoom() const { return zoom; } void setZoom(float factor); void centerList(); // set listPos.x so that the view will be in the centter - const string& getFile(sizt id) const { return pics[id].first; } + void saveCurPage(); virtual vec2i wgtPosition(sizt id) const override; virtual vec2i wgtSize(sizt id) const override; diff --git a/src/utils/settings.cpp b/src/utils/settings.cpp index 0c945fb4..85ced71c 100644 --- a/src/utils/settings.cpp +++ b/src/utils/settings.cpp @@ -1,5 +1,19 @@ #include "engine/world.h" +// DIRECTION + +Direction::Direction(Dir direction) : + dir(direction) +{} + +string Direction::toString() const { + return enumToStr(Default::directionNames, dir); +} + +void Direction::set(const string& str) { + dir = strToEnum(Default::directionNames, str); +} + // BINDING Binding::Binding() : @@ -88,12 +102,12 @@ void Binding::setDefaultSelf(Type type) { setKey(Default::keyScrollSlow); setJbutton(Default::jbuttonScrollSlow); setGbutton(Default::gbuttonScrollSlow); - } else if (type == Type::pageUp) { - setBcall(&ProgState::eventPageUp); - setKey(Default::keyPageUp); - } else if (type == Type::pageDown) { - setBcall(&ProgState::eventPageDown); - setKey(Default::keyPageDown); + } else if (type == Type::nextPage) { + setBcall(&ProgState::eventNextPage); + setKey(Default::keyNextPage); + } else if (type == Type::prevPage) { + setBcall(&ProgState::eventPrevPage); + setKey(Default::keyPrevPage); } else if (type == Type::zoomIn) { setBcall(&ProgState::eventZoomIn); setKey(Default::keyZoomIn); @@ -109,6 +123,12 @@ void Binding::setDefaultSelf(Type type) { setKey(Default::keyZoomReset); setJbutton(Default::jbuttonZoomReset); setGbutton(Default::gbuttonZoomReset); + } else if (type == Type::toStart) { + setBcall(&ProgState::eventToStart); + setKey(Default::keyToStart); + } else if (type == Type::toEnd) { + setBcall(&ProgState::eventToEnd); + setKey(Default::keyToEnd); } else if (type == Type::nextDir) { setBcall(&ProgState::eventNextDir); setKey(Default::keyNextDir); @@ -124,6 +144,9 @@ void Binding::setDefaultSelf(Type type) { setKey(Default::keyFullscreen); setJbutton(Default::jbuttonFullscreen); setGbutton(Default::gbuttonFullscreen); + } else if (type == Type::refresh) { + setBcall(&ProgState::eventRefresh); + setKey(Default::keyRefresh); } } @@ -196,10 +219,12 @@ void Binding::setAcall(SACall call) { // SETTINGS -Settings::Settings(bool maximized, bool fullscreen, const vec2i& resolution, const Direction& direction, const string& theme, const string& font, const string& language, const string& library, const string& renderer, const vec2f& speed, int16 deadzone) : +Settings::Settings(bool maximized, bool fullscreen, const vec2i& resolution, const Direction& direction, float zoom, int spacing, const string& theme, const string& font, const string& language, const string& library, const string& renderer, const vec2f& speed, int16 deadzone) : maximized(maximized), fullscreen(fullscreen), direction(direction), + zoom(zoom), + spacing(spacing), resolution(resolution), renderer(renderer), scrollSpeed(speed) diff --git a/src/utils/settings.h b/src/utils/settings.h index 091ae504..5810dbd8 100644 --- a/src/utils/settings.h +++ b/src/utils/settings.h @@ -21,7 +21,7 @@ class Direction { left, right }; - Direction(Dir direction=Direction::up) : dir(direction) {} + Direction(Dir direction=Direction::up); operator Dir() const { return dir; } @@ -30,6 +30,9 @@ class Direction { bool positive() const { return dir % 2; } bool negative() const { return !positive(); } + string toString() const; + void set(const string& str); + private: Dir dir; }; @@ -54,16 +57,20 @@ class Binding { centerView, scrollFast, scrollSlow, - pageUp, - pageDown, + nextPage, + prevPage, zoomIn, zoomOut, zoomReset, + toStart, + toEnd, nextDir, prevDir, fullscreen, + refresh, numBindings }; + enum Assignment : uint8 { ASG_NONE = 0x0, ASG_KEY = 0x1, @@ -143,7 +150,7 @@ inline Binding::Assignment operator|=(Binding::Assignment& a, Binding::Assignmen class Settings { public: - Settings(bool maximized=Default::maximized, bool fullscreen=Default::fullscreen, const vec2i& resolution=Default::resolution, const Direction& direction=Direction::down, const string& theme="", const string& font=Default::font, const string& language=Default::language, const string& library="", const string& renderer="", const vec2f& speed=Default::scrollSpeed, int16 deadzone=Default::controllerDeadzone); + Settings(bool maximized=Default::maximized, bool fullscreen=Default::fullscreen, const vec2i& resolution=Default::resolution, const Direction& direction=Direction::down, float zoom=Default::zoom, int spacing=Default::spacing, const string& theme="", const string& font=Default::font, const string& language=Default::language, const string& library="", const string& renderer="", const vec2f& speed=Default::scrollSpeed, int16 deadzone=Default::controllerDeadzone); string getResolutionString() const; void setResolution(const string& line); @@ -168,6 +175,8 @@ class Settings { bool maximized, fullscreen; Direction direction; + float zoom; + int spacing; vec2i resolution; string renderer; vec2f scrollSpeed; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 474604fa..1defc2d8 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -1,74 +1,80 @@ #include "engine/world.h" #include #include +#ifndef _WIN32 +#include +#endif + +int strcicmp(const string& a, const string& b) { +#ifdef _WIN32 + return _stricmp(a.c_str(), b.c_str()); +#else + return strcasecmp(a.c_str(), b.c_str()); +#endif +} + +static int natCompareRight(const char* a, const char* b) { + for (int bias = 0;; a++, b++) { + if (!isDigit(*a) && !isDigit(*b)) + return bias; + else if (!isDigit(*a)) + return -1; + else if (!isDigit(*b)) + return +1; + else if (*a < *b) { + if (!bias) + bias = -1; + } else if (*a > *b) { + if (!bias) + bias = +1; + } else if (!*a && !*b) + return bias; + } + return 0; +} -int strcicmp(const char* a, const char* b) { - for (; *a && toupper(*a) == toupper(*b); a++, b++); - return *reinterpret_cast(a) - *reinterpret_cast(b); +static int natCompareLeft(const char* a, const char* b) { + for (;; a++, b++) { + if (!isDigit(*a) && !isDigit(*b)) + return 0; + else if (!isDigit(*a)) + return -1; + else if (!isDigit(*b)) + return +1; + else if (*a < *b) + return -1; + else if (*a > *b) + return +1; + } + return 0; } -static int natCompareRight(const char* a, const char* b) { - for (int bias = 0;; a++, b++) { - if (!isDigit(*a) && !isDigit(*b)) - return bias; - else if (!isDigit(*a)) - return -1; - else if (!isDigit(*b)) - return +1; - else if (*a < *b) { - if (!bias) - bias = -1; - } else if (*a > *b) { - if (!bias) - bias = +1; - } else if (!*a && !*b) - return bias; - } - return 0; -} - -static int natCompareLeft(const char* a, const char* b) { - for (;; a++, b++) { - if (!isDigit(*a) && !isDigit(*b)) - return 0; - else if (!isDigit(*a)) - return -1; - else if (!isDigit(*b)) - return +1; - else if (*a < *b) - return -1; - else if (*a > *b) - return +1; - } - return 0; -} - -int strnatcmp(const char* a, const char* b) { - for (;; a++, b++) { - char ca = *a; - char cb = *b; - while (isSpace(ca)) - ca = *++a; - while (isSpace(cb)) - cb = *++b; - - if (isDigit(ca) && isDigit(cb)) { - if (ca == '0' || cb == '0') { - if (int result = natCompareLeft(a, b)) - return result; - } else { - if (int result = natCompareRight(a, b)) - return result; - } - } - - if (!ca && !cb) - return 0; - if (ca < cb) - return -1; - if (ca > cb) - return +1; - } +int strnatcmp(const char* a, const char* b) { + for (;; a++, b++) { + char ca = *a; + char cb = *b; + while (isSpace(ca)) + ca = *++a; + while (isSpace(cb)) + cb = *++b; + + if (isDigit(ca) && isDigit(cb)) { + if (ca == '0' || cb == '0') { + if (int result = natCompareLeft(a, b)) + return result; + } else { + if (int result = natCompareRight(a, b)) + return result; + } + } + + if (!ca && !cb) + return 0; + if (ca < cb) + return -1; + if (ca > cb) + return +1; + } } bool isAbsolute(const string& path) { @@ -272,7 +278,7 @@ string jtHatToStr(uint8 jhat) { uint8 jtStrToHat(const string& str) { for (const pair& it : Default::hatNames) - if (!strcicmp(it.second.c_str(), str.c_str())) + if (!strcicmp(it.second, str)) return it.first; return 0x10; } @@ -281,4 +287,4 @@ sizt nextIndex(sizt id, sizt lim, bool fwd) { if (fwd) return id == lim - 1 ? 0 : id + 1; return id == 0 ? lim - 1 : id - 1; -} +} diff --git a/src/utils/utils.h b/src/utils/utils.h index f16db4ba..5c5e7463 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -3,7 +3,7 @@ #include "settings.h" // files and strings -int strcicmp(const char* a, const char* b); // case insensitive check if strings are equal +int strcicmp(const string& a, const string& b); // case insensitive check if strings are equal int strnatcmp(const char* a, const char* b); // natural string compare inline bool strnatless(const string& a, const string& b) { return strnatcmp(a.c_str(), b.c_str()) < 0; } bool isAbsolute(const string& path); @@ -68,6 +68,16 @@ vec2 bringUnder(const vec2& val, const vec2& max) { return vec2(bringUnder(val.x, max.x), bringUnder(val.y, max.y)); } +template // correct val if out of range. returns true if value already in range +T bringOver(T val, T min) { + return (val < min) ? min : val; +} + +template +vec2 bringOver(const vec2& val, const vec2& min) { + return vec2(bringUnder(val.x, min.x), bringUnder(val.y, min.y)); +} + // convertions string wtos(const wstring& wstr); wstring stow(const string& str); @@ -78,15 +88,15 @@ uint8 jtStrToHat(const string& str); template string enumToStr(const vector& names, T id) { - return sizt(id) >= names.size() ? "invalid" : names[sizt(id)]; + return static_cast(id) < names.size() ? names[static_cast(id)] : ""; } template T strToEnum(const vector& names, string str) { for (sizt i = 0; i < names.size(); i++) - if (!strcicmp(names[i].c_str(), str.c_str())) - return T(i); - return T(names.size()); + if (!strcicmp(names[i], str)) + return static_cast(i); + return static_cast(SIZE_MAX); } template diff --git a/src/utils/vec2.h b/src/utils/vec2.h index b898ef03..eb4a30d8 100644 --- a/src/utils/vec2.h +++ b/src/utils/vec2.h @@ -163,7 +163,7 @@ struct vec2 { } T length() const { - return sqrt(x*x + y*y); + return std::sqrt(x*x + y*y); } vec2 normalize() const { @@ -406,8 +406,8 @@ vec2 reflect(const vec2& vec, vec2 nrm) { template vec2 rotate(const vec2& vec, const T& ang) { - T sa = sin(ang); - T ca = cos(ang); + T sa = std::sin(ang); + T ca = std::cos(ang); return vec2(vec.x * ca - vec.y * sa, vec.x * sa + vec.y * ca); } diff --git a/src/utils/widgets.cpp b/src/utils/widgets.cpp index 4e9754e4..452e42e4 100644 --- a/src/utils/widgets.cpp +++ b/src/utils/widgets.cpp @@ -466,20 +466,20 @@ void LineEdit::cancel() { sizt LineEdit::findWordStart() { sizt i = cpos; - if (text[i] != ' ' && i > 0 && text[i-1] == ' ') // skip if first letter of word + if (!isSpace(text[i]) && i > 0 && isSpace(text[i-1])) // skip if first letter of word i--; - while (text[i] == ' ' && i > 0) // skip first spaces + while (isSpace(text[i]) && i > 0) // skip first spaces i--; - while (text[i] != ' ' && i > 0) // skip word + while (!isSpace(text[i]) && i > 0) // skip word i--; - return i == 0 ? i : i+1; // correct position if necessary + return i == 0 ? i : i + 1; // correct position if necessary } sizt LineEdit::findWordEnd() { sizt i = cpos; - while (text[i] == ' ' && i < text.length()) // skip first spaces + while (isSpace(text[i]) && i < text.length()) // skip first spaces i++; - while (text[i] != ' ' && i < text.length()) // skip word + while (!isSpace(text[i]) && i < text.length()) // skip word i++; return i; }