From 11ab39e3c1db277c68c92a0a6a8e6cd7fa0bc813 Mon Sep 17 00:00:00 2001 From: karwler Date: Tue, 19 Mar 2019 20:00:27 +0100 Subject: [PATCH] Minor code improvements * fix file writing * make more use of SDL * add wannabe boss key * forgot to delete translations before --- README.md | 6 +- rsc/data/languages/Deutsch.ini | 23 ------ rsc/data/languages/Polski.ini | 23 ------ ...1\201\321\201\320\272\320\270\320\271.ini" | 23 ------ src/engine/drawSys.cpp | 23 +++--- src/engine/fileSys.cpp | 30 +++----- src/engine/fileSys.h | 16 ++-- src/engine/scene.cpp | 28 +++---- src/engine/scene.h | 2 +- src/engine/windowSys.cpp | 9 ++- src/engine/windowSys.h | 1 + src/prog/progs.cpp | 4 + src/prog/progs.h | 1 + src/utils/layouts.cpp | 6 +- src/utils/layouts.h | 2 +- src/utils/settings.cpp | 9 ++- src/utils/settings.h | 39 +++++----- src/utils/utils.cpp | 75 ++++++------------- src/utils/utils.h | 48 ++++++------ src/utils/vec2.h | 2 +- src/utils/widgets.cpp | 6 +- src/utils/widgets.h | 1 + 22 files changed, 148 insertions(+), 229 deletions(-) delete mode 100644 rsc/data/languages/Deutsch.ini delete mode 100644 rsc/data/languages/Polski.ini delete mode 100644 "rsc/data/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.ini" diff --git a/README.md b/README.md index 09e5de94..d75d2591 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # VertiRead A simple comic reader for Linux and Windows. It's basically just an image viewer that shows all pictures in a directory/archive. -Currently supported file formats are JPG, PNG, TIFF, WEBP and archives. +Currently supported file formats are whatever SDL2_image and libarchive support. Used libraries are SDL2, SDL2_image, SDL2_ttf, libarchive and by extension libjpeg, libpng, libtiff, libwebp, FreeType and zlib. The CMakeLists.txt is written for at least CMake 3.10.2 with Clang, GCC or MSVC which need to support C++17. @@ -30,3 +30,7 @@ The reader has a hidden side panel on the left. The direction in which pictures in the reader are stacked can be set in the settings menu. The program supports keyboard and controller bindings. DirectInput and XInput are handled separately. The bindings can be changed in the settings. To reset certain settings, edit or delete the corresponding ini files in the settings directory or use the reset button in the settings menu to reset all settings. + +## Supported files +- images: bmp, gif, jpg, lbm, pcx, png, pnm, svg, tga, tiff, webp, xcf, xpm, xv +- archives: 7z, ar, cab, cpio, empty, ISO9660, lha, lzh, mtree, pax, rar, raw, tar, xar, zip \ No newline at end of file diff --git a/rsc/data/languages/Deutsch.ini b/rsc/data/languages/Deutsch.ini deleted file mode 100644 index 5b0c7423..00000000 --- a/rsc/data/languages/Deutsch.ini +++ /dev/null @@ -1,23 +0,0 @@ -settings=Einstellungen -exit=beenden -back=zurück -ok=ok -set=einstellen -up=hoch -direction=Richtung -zoom=Zoom -spacing=Abstand -fullscreen=Vollbild -size=Größe -portrait=Porträt -landscape=Landschaft -square=Quadrat -fill=füllen -theme=Aussehen -language=Sprache -font=Schriftart -library=Bibliothek -renderer=Renderer -scroll speed=Scrollgeschwindigkeit -deadzone=Deadzone -reset=zurücksetzen \ No newline at end of file diff --git a/rsc/data/languages/Polski.ini b/rsc/data/languages/Polski.ini deleted file mode 100644 index 6b85bb5e..00000000 --- a/rsc/data/languages/Polski.ini +++ /dev/null @@ -1,23 +0,0 @@ -settings=ustawienia -exit=zamknij -back=wróć -ok=ok -set=ustaw -up=do góry -direction=kierunek -zoom=powiększenie -spacing=odstęp -fullscreen=pełny ekran -size=rozmiar -portrait=portret -landscape=krajobraz -square=kwadrat -fill=wypełnij -theme=wygląd -language=język -font=czcionka -library=biblioteka -renderer=render -scroll speed=prędkość przewijania -deadzone=martwa strefa -reset=zresetuj \ No newline at end of file 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" deleted file mode 100644 index 3f0d6d46..00000000 --- "a/rsc/data/languages/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.ini" +++ /dev/null @@ -1,23 +0,0 @@ -settings=параметры -exit=выход -back=назад -ok=хорошо -set=устанавливай -up=вверх -direction=направление -zoom=зум -spacing=пространство -fullscreen=полноэкранный -size=размер -portrait=портрет -landscape=пейзаж -square=квадрат -fill=заполний -theme=внешний вид -language=язык -font=шрифт -library=библиотека -renderer=визуализатор -scroll speed=скорость прокрутки -deadzone=мертвая зона -reset=сбросий \ No newline at end of file diff --git a/src/engine/drawSys.cpp b/src/engine/drawSys.cpp index 978f821d..f48fa584 100644 --- a/src/engine/drawSys.cpp +++ b/src/engine/drawSys.cpp @@ -134,26 +134,26 @@ void DrawSys::drawWidgets() { void DrawSys::drawPicture(const Picture* wgt) { if (wgt->showBG) - drawRect(wgt->rect().getOverlap(wgt->frame()), wgt->color()); + drawRect(wgt->rect().intersect(wgt->frame()), wgt->color()); if (wgt->tex) drawImage(wgt->tex, wgt->texRect(), wgt->frame()); } void DrawSys::drawCheckBox(const CheckBox* wgt) { drawPicture(wgt); // draw background - drawRect(wgt->boxRect().getOverlap(wgt->frame()), wgt->boxColor()); // draw checkbox + drawRect(wgt->boxRect().intersect(wgt->frame()), wgt->boxColor()); // draw checkbox } void DrawSys::drawSlider(const Slider* wgt) { Rect frame = wgt->frame(); drawPicture(wgt); // draw background - drawRect(wgt->barRect().getOverlap(frame), Color::dark); // draw bar - drawRect(wgt->sliderRect().getOverlap(frame), Color::light); // draw slider + drawRect(wgt->barRect().intersect(frame), Color::dark); // draw bar + drawRect(wgt->sliderRect().intersect(frame), Color::light); // draw slider } void DrawSys::drawProgressBar(const ProgressBar* wgt) { drawRect(wgt->rect(), Color::normal); // draw background - drawRect(wgt->barRect().getOverlap(wgt->frame()), Color::light); // draw bar + drawRect(wgt->barRect().intersect(wgt->frame()), Color::light); // draw bar } void DrawSys::drawLabel(const Label* wgt) { @@ -217,13 +217,12 @@ void DrawSys::drawImage(SDL_Texture* tex, const Rect& rect, const Rect& frame) { } SDL_Texture* DrawSys::renderText(const string& text, int height) { - if (text.empty()) - return nullptr; - - SDL_Surface* surf = TTF_RenderUTF8_Blended(fonts.getFont(height), text.c_str(), colors[uint8(Color::text)]); - SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf); - SDL_FreeSurface(surf); - return tex; + if (SDL_Surface* surf = TTF_RenderUTF8_Blended(fonts.getFont(height), text.c_str(), colors[uint8(Color::text)])) { + SDL_Texture* tex = SDL_CreateTextureFromSurface(renderer, surf); + SDL_FreeSurface(surf); + return tex; + } + return nullptr; } vector DrawSys::loadTexturesDirectory(const string& drc) { diff --git a/src/engine/fileSys.cpp b/src/engine/fileSys.cpp index ab3014b4..0f5f497d 100644 --- a/src/engine/fileSys.cpp +++ b/src/engine/fileSys.cpp @@ -312,8 +312,8 @@ string FileSys::readTextFile(const string& file, bool printMessage) { return text; } -bool FileSys::writeTextFile(const std::string& file, const string& text) { - if (FILE* ofh = fopen(file.c_str(), defaultFrMode)) { +bool FileSys::writeTextFile(const string& file, const string& text) { + if (FILE* ofh = fopen(file.c_str(), defaultFwMode)) { fwrite(text.c_str(), sizeof(char), text.length(), ofh); fclose(ofh); } else { @@ -324,7 +324,7 @@ bool FileSys::writeTextFile(const std::string& file, const string& text) { } bool FileSys::writeTextFile(const string& file, const vector& lines) { - if (FILE* ofh = fopen(file.c_str(), defaultFrMode)) { + if (FILE* ofh = fopen(file.c_str(), defaultFwMode)) { for (const string& it : lines) fputs(string(it + '\n').c_str(), ofh); fclose(ofh); @@ -594,24 +594,18 @@ int FileSys::moveContentThreaded(void* data) { } void FileSys::setWorkingDir() { -#ifdef _WIN32 - wchar* buf = new wchar[MAX_PATH]; - DWORD len = GetModuleFileNameW(nullptr, buf, MAX_PATH); - if (!len || len == MAX_PATH) { - delete[] buf; - buf = new wchar[pathMax]; - len = GetModuleFileNameW(nullptr, buf, pathMax); + char* path = SDL_GetBasePath(); + if (!path) { + std::cerr << SDL_GetError() << std::endl; + return; } - while (len > 0 && buf[--len] != dsep); // terminate path stirng at last dsep - buf[len] = '\0'; - if (!len || _wchdir(buf)) - std::cerr << "failed to set working directory" << std::endl; +#ifdef _WIN32 + if (_wchdir(stow(path).c_str())) #else - char* buf = new char[PATH_MAX]; - if (sizet len = sizet(readlink(linkExe, buf, PATH_MAX)); len > PATH_MAX || chdir(parentPath(string(buf, buf + len)).c_str())) - std::cerr << "failed to set working directory" << std::endl; + if (chdir(path)) #endif - delete[] buf; + std::cerr << "failed to set working directory" << std::endl; + SDL_free(path); } string FileSys::findFont(const string& font) { diff --git a/src/engine/fileSys.h b/src/engine/fileSys.h index 4366325b..ff47db92 100644 --- a/src/engine/fileSys.h +++ b/src/engine/fileSys.h @@ -25,31 +25,31 @@ enum FileType : uint8 { FTYPE_ANY = 0xFF }; -inline FileType operator~(FileType a) { +inline constexpr FileType operator~(FileType a) { return FileType(~uint8(a)); } -inline FileType operator&(FileType a, FileType b) { +inline constexpr FileType operator&(FileType a, FileType b) { return FileType(uint8(a) & uint8(b)); } -inline FileType operator&=(FileType& a, FileType b) { +inline constexpr FileType operator&=(FileType& a, FileType b) { return a = FileType(uint8(a) & uint8(b)); } -inline FileType operator^(FileType a, FileType b) { +inline constexpr FileType operator^(FileType a, FileType b) { return FileType(uint8(a) ^ uint8(b)); } -inline FileType operator^=(FileType& a, FileType b) { +inline constexpr FileType operator^=(FileType& a, FileType b) { return a = FileType(uint8(a) ^ uint8(b)); } -inline FileType operator|(FileType a, FileType b) { +inline constexpr FileType operator|(FileType a, FileType b) { return FileType(uint8(a) | uint8(b)); } -inline FileType operator|=(FileType& a, FileType b) { +inline constexpr FileType operator|=(FileType& a, FileType b) { return a = FileType(uint8(a) | uint8(b)); } @@ -146,11 +146,9 @@ class FileSys { #ifdef _WIN32 static const array takenFilenames; static constexpr sizet drivesMax = 26; - static constexpr sizet pathMax = 32767; static constexpr sizet fnameMax = 255; #else static constexpr sizet fnameMax = NAME_MAX; - static constexpr char linkExe[] = "/proc/self/exe"; #endif static constexpr char fileThemes[] = "themes.ini"; static constexpr char fileSettings[] = "settings.ini"; diff --git a/src/engine/scene.cpp b/src/engine/scene.cpp index 21ec23d6..bc7a9d18 100644 --- a/src/engine/scene.cpp +++ b/src/engine/scene.cpp @@ -25,7 +25,7 @@ void Scene::tick(float dSec) { } void Scene::onMouseMove(const vec2i& mPos, const vec2i& mMov) { - setSelected(mPos, topLayout(mPos)); + select = getSelected(mPos, topLayout(mPos)); if (capture) capture->onDrag(mPos, mMov); @@ -45,7 +45,7 @@ void Scene::onMouseDown(const vec2i& mPos, uint8 mBut, uint8 mCnt) { capture = nullptr; } - setSelected(mPos, topLayout(mPos)); // update in case selection has changed through keys while cursor remained at the old position + select = getSelected(mPos, topLayout(mPos)); // update in case selection has changed through keys while cursor remained at the old position if (mCnt == 1) { stamps[mBut] = ClickStamp(select, getSelectedScrollArea(), mPos); if (stamps[mBut].area) // area goes first so widget can overwrite it's capture @@ -115,15 +115,17 @@ void Scene::setPopup(Popup* newPopup, Widget* newCapture) { onMouseMove(mousePos(), 0); } -void Scene::setSelected(const vec2i& mPos, Layout* box) { - Rect frame = box->frame(); - if (vector::const_iterator it = std::find_if(box->getWidgets().begin(), box->getWidgets().end(), [&frame, &mPos](const Widget* wi) -> bool { return wi->rect().getOverlap(frame).overlap(mPos); }); it != box->getWidgets().end()) { - if (Layout* lay = dynamic_cast(*it)) - setSelected(mPos, lay); - else - select = (*it)->navSelectable() ? *it : box; - } else - select = box; +Widget* Scene::getSelected(const vec2i& mPos, Layout* box) { + for (;;) { + Rect frame = box->frame(); + if (vector::const_iterator it = std::find_if(box->getWidgets().begin(), box->getWidgets().end(), [&frame, &mPos](const Widget* wi) -> bool { return wi->rect().intersect(frame).contain(mPos); }); it != box->getWidgets().end()) { + if (Layout* lay = dynamic_cast(*it)) + box = lay; + else + return (*it)->navSelectable() ? *it : box; + } else + return box; + } } ScrollArea* Scene::getSelectedScrollArea() const { @@ -141,8 +143,8 @@ bool Scene::overlayFocused(const vec2i& mPos) { return false; if (overlay->on) - return overlay->rect().overlap(mPos) ? true : overlay->on = false; - return overlay->actRect().overlap(mPos) ? overlay->on = true : false; + return overlay->rect().contain(mPos) ? true : overlay->on = false; + return overlay->actRect().contain(mPos) ? overlay->on = true : false; } void Scene::selectFirst() { diff --git a/src/engine/scene.h b/src/engine/scene.h index 2f545318..33cc4bbd 100644 --- a/src/engine/scene.h +++ b/src/engine/scene.h @@ -50,7 +50,7 @@ class Scene { bool cursorInClickRange(const vec2i& mPos, uint8 mBut); private: - void setSelected(const vec2i& mPos, Layout* box); + Widget* getSelected(const vec2i& mPos, Layout* box); ScrollArea* getSelectedScrollArea() const; bool overlayFocused(const vec2i& mPos); Layout* topLayout(const vec2i& mPos); diff --git a/src/engine/windowSys.cpp b/src/engine/windowSys.cpp index 981525a0..071e8483 100644 --- a/src/engine/windowSys.cpp +++ b/src/engine/windowSys.cpp @@ -23,7 +23,7 @@ void WindowSys::init() { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER)) throw std::runtime_error(string("Failed to initialize SDL:\n") + SDL_GetError()); if (TTF_Init()) - throw std::runtime_error(string("Failed to initialize fonts:\n") + SDL_GetError()); + throw std::runtime_error(string("Failed to initialize fonts:\n") + TTF_GetError()); SDL_StopTextInput(); // for some reason TextInput is on int flags = IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF | IMG_INIT_WEBP); @@ -193,6 +193,13 @@ void WindowSys::moveCursor(const vec2i& mov) { SDL_WarpMouseInWindow(window, px + mov.x, py + mov.y); } +void WindowSys::toggleOpacity() { + if (float val; !SDL_GetWindowOpacity(window, &val)) + SDL_SetWindowOpacity(window, val < 1.f ? 1.f : 0.f); + else + SDL_MinimizeWindow(window); +} + void WindowSys::setFullscreen(bool on) { sets->fullscreen = on; SDL_SetWindowFullscreen(window, on ? SDL_GetWindowFlags(window) | SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_GetWindowFlags(window) & uint32(~SDL_WINDOW_FULLSCREEN_DESKTOP)); diff --git a/src/engine/windowSys.h b/src/engine/windowSys.h index fda9ea22..55b289b7 100644 --- a/src/engine/windowSys.h +++ b/src/engine/windowSys.h @@ -40,6 +40,7 @@ class WindowSys { vec2i displayResolution() const; void setWindowPos(const vec2i& pos); void moveCursor(const vec2i& mov); + void toggleOpacity(); void setFullscreen(bool on); void setResolution(const vec2i& res); void setRenderer(const string& name); diff --git a/src/prog/progs.cpp b/src/prog/progs.cpp index b2f89dfd..d14f7c42 100644 --- a/src/prog/progs.cpp +++ b/src/prog/progs.cpp @@ -82,6 +82,10 @@ void ProgState::eventHide() { World::sets()->showHidden = !World::sets()->showHidden; } +void ProgState::eventBoss() { + World::winSys()->toggleOpacity(); +} + void ProgState::eventRefresh() { World::scene()->resetLayouts(); } diff --git a/src/prog/progs.h b/src/prog/progs.h index 1f5dbd40..59ad75d0 100644 --- a/src/prog/progs.h +++ b/src/prog/progs.h @@ -55,6 +55,7 @@ class ProgState { virtual void eventPrevDir() {} virtual void eventFullscreen(); virtual void eventHide(); + void eventBoss(); void eventRefresh(); virtual void eventFileDrop(const string&) {} virtual void eventClosing() {} diff --git a/src/utils/layouts.cpp b/src/utils/layouts.cpp index 57b7d865..cec3ac40 100644 --- a/src/utils/layouts.cpp +++ b/src/utils/layouts.cpp @@ -274,7 +274,7 @@ void ScrollArea::onHold(const vec2i& mPos, uint8 mBut) { if (mBut == SDL_BUTTON_LEFT) { // check scroll bar left click World::scene()->capture = this; - if (draggingSlider = barRect().overlap(mPos)) { + if (draggingSlider = barRect().contain(mPos)) { sizet di = direction.vertical(); if (int sp = sliderPos(), ss = sliderSize(); outRange(mPos[di], sp, sp + ss)) // if mouse outside of slider but inside bar setSlider(mPos[di] - ss /2); @@ -386,7 +386,7 @@ void ScrollArea::scrollToLimit(bool start) { } Rect ScrollArea::frame() const { - return parent ? rect().getOverlap(parent->frame()) : rect(); + return parent ? rect().intersect(parent->frame()) : rect(); } vec2i ScrollArea::wgtPosition(sizet id) const { @@ -625,7 +625,7 @@ void ReaderBox::postInit() { void ReaderBox::onMouseMove(const vec2i& mPos, const vec2i& mMov) { Layout::onMouseMove(mPos, mMov); - countDown = World::scene()->cursorDisableable() && rect().overlap(mPos) && !showBar() && World::scene()->capture != this && cursorTimer > 0.f; + countDown = World::scene()->cursorDisableable() && rect().contain(mPos) && !showBar() && World::scene()->capture != this && cursorTimer > 0.f; if (cursorTimer < menuHideTimeout) { cursorTimer = menuHideTimeout; SDL_ShowCursor(SDL_ENABLE); diff --git a/src/utils/layouts.h b/src/utils/layouts.h index b309aec1..d264676b 100644 --- a/src/utils/layouts.h +++ b/src/utils/layouts.h @@ -234,7 +234,7 @@ class ReaderBox : public ScrollArea { }; inline bool ReaderBox::showBar() const { - return barRect().overlap(mousePos()) || draggingSlider; + return barRect().contain(mousePos()) || draggingSlider; } inline float ReaderBox::getZoom() const { diff --git a/src/utils/settings.cpp b/src/utils/settings.cpp index bc832ad0..df754945 100644 --- a/src/utils/settings.cpp +++ b/src/utils/settings.cpp @@ -40,6 +40,7 @@ const array Binding::names = { "prev directory", "fullscreen", "show hidden", + "boss", "refresh" }; @@ -179,13 +180,13 @@ void Binding::setDefaultSelf(Type type) { break; case Type::nextDir: setBcall(&ProgState::eventNextDir); - setKey(SDL_SCANCODE_N); + setKey(SDL_SCANCODE_D); setJbutton(7); setGaxis(SDL_CONTROLLER_AXIS_TRIGGERRIGHT, true); break; case Type::prevDir: setBcall(&ProgState::eventPrevDir); - setKey(SDL_SCANCODE_B); + setKey(SDL_SCANCODE_A); setJbutton(6); setGaxis(SDL_CONTROLLER_AXIS_TRIGGERLEFT, true); break; @@ -199,6 +200,10 @@ void Binding::setDefaultSelf(Type type) { setBcall(&ProgState::eventHide); setKey(SDL_SCANCODE_H); break; + case Type::boss: + setBcall(&ProgState::eventBoss); + setKey(SDL_SCANCODE_B); + break; case Type::refresh: setBcall(&ProgState::eventRefresh); setKey(SDL_SCANCODE_F5); diff --git a/src/utils/settings.h b/src/utils/settings.h index dc22bbba..b3cd6849 100644 --- a/src/utils/settings.h +++ b/src/utils/settings.h @@ -25,37 +25,37 @@ class Direction { Dir dir; public: - Direction(Dir direction = Direction::up); + constexpr Direction(Dir direction = Direction::up); - operator Dir() const; + constexpr operator Dir() const; - bool vertical() const; - bool horizontal() const; - bool positive() const; - bool negative() const; + constexpr bool vertical() const; + constexpr bool horizontal() const; + constexpr bool positive() const; + constexpr bool negative() const; }; -inline Direction::Direction(Dir direction) : +inline constexpr Direction::Direction(Dir direction) : dir(direction) {} -inline Direction::operator Dir() const { +inline constexpr Direction::operator Dir() const { return dir; } -inline bool Direction::vertical() const { +inline bool constexpr Direction::vertical() const { return dir <= down; } -inline bool Direction::horizontal() const { +inline bool constexpr Direction::horizontal() const { return dir >= left; } -inline bool Direction::positive() const { +inline bool constexpr Direction::positive() const { return dir & 1; } -inline bool Direction::negative() const { +inline bool constexpr Direction::negative() const { return !positive(); } @@ -90,6 +90,7 @@ class Binding { prevDir, fullscreen, hide, + boss, refresh }; static const array names; @@ -164,31 +165,31 @@ class Binding { void setAcall(SACall call); }; -inline Binding::Assignment operator~(Binding::Assignment a) { +inline constexpr Binding::Assignment operator~(Binding::Assignment a) { return Binding::Assignment(~uint8(a)); } -inline Binding::Assignment operator&(Binding::Assignment a, Binding::Assignment b) { +inline constexpr Binding::Assignment operator&(Binding::Assignment a, Binding::Assignment b) { return Binding::Assignment(uint8(a) & uint8(b)); } -inline Binding::Assignment operator&=(Binding::Assignment& a, Binding::Assignment b) { +inline constexpr Binding::Assignment operator&=(Binding::Assignment& a, Binding::Assignment b) { return a = Binding::Assignment(uint8(a) & uint8(b)); } -inline Binding::Assignment operator^(Binding::Assignment a, Binding::Assignment b) { +inline constexpr Binding::Assignment operator^(Binding::Assignment a, Binding::Assignment b) { return Binding::Assignment(uint8(a) ^ uint8(b)); } -inline Binding::Assignment operator^=(Binding::Assignment& a, Binding::Assignment b) { +inline constexpr Binding::Assignment operator^=(Binding::Assignment& a, Binding::Assignment b) { return a = Binding::Assignment(uint8(a) ^ uint8(b)); } -inline Binding::Assignment operator|(Binding::Assignment a, Binding::Assignment b) { +inline constexpr Binding::Assignment operator|(Binding::Assignment a, Binding::Assignment b) { return Binding::Assignment(uint8(a) | uint8(b)); } -inline Binding::Assignment operator|=(Binding::Assignment& a, Binding::Assignment b) { +inline constexpr Binding::Assignment operator|=(Binding::Assignment& a, Binding::Assignment b) { return a = Binding::Assignment(uint8(a) | uint8(b)); } diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 208ac451..32655760 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -10,65 +10,21 @@ vector getAvailibleRenderers() { return renderers; } -bool Rect::overlap(const Rect& rect, vec2i& sback, vec2i& rback) const { - if (w <= 0 || h <= 0 || rect.w <= 0 || rect.h <= 0) // idfk - return false; - - sback = back(); - rback = rect.back(); - return x < rback.x && y < rback.y && sback.x >= rect.x && sback.y >= rect.y; -} - -Rect Rect::crop(const Rect& frame) { - vec2i rback, fback; - if (!overlap(frame, rback, fback)) +Rect Rect::crop(const Rect& rect) { + Rect isct; + if (!SDL_IntersectRect(this, &rect, &isct)) return *this = Rect(0); - Rect crop(0); // crop rect if it's boundaries are out of frame - if (x < frame.x) { // left - crop.x = frame.x - x; - x = frame.x; - w -= crop.x; - } - if (rback.x > fback.x) { // right - crop.w = rback.x - fback.x; - w -= crop.w; - } - if (y < frame.y) { // top - crop.y = frame.y - y; - y = frame.y; - h -= crop.y; - } - if (rback.y > fback.y) { // bottom - crop.h = rback.y - fback.y; - h -= crop.h; - } - crop.size() += crop.pos(); // get full width and height of crop + vec2i te = end(), ie = isct.end(); + Rect crop; + crop.x = isct.x > x ? isct.x - x : 0; + crop.y = isct.y > y ? isct.y - y : 0; + crop.w = ie.x < te.x ? te.x - ie.x + crop.x : 0; + crop.h = ie.y < te.y ? te.y - ie.y + crop.y : 0; + *this = isct; return crop; } -Rect Rect::getOverlap(const Rect& frame) const { - Rect rect = *this; - vec2i rback, fback; - if (!rect.overlap(frame, rback, fback)) - return Rect(0); - - // crop rect if it's boundaries are out of frame - if (rect.x < frame.x) { // left - rect.w -= frame.x - rect.x; - rect.x = frame.x; - } - if (rback.x > fback.x) // right - rect.w -= rback.x - fback.x; - if (rect.y < frame.y) { // top - rect.h -= frame.y - rect.y; - rect.y = frame.y; - } - if (rback.y > fback.y) // bottom - rect.h -= rback.y - fback.y; - return rect; -} - Thread::Thread(int (*func)(void*), void* data) : data(data) { @@ -275,6 +231,17 @@ string wtos(const wstring& src) { return dst; } +wstring stow(const char* src) { + int len = MultiByteToWideChar(CP_UTF8, 0, src, -1, nullptr, 0); + if (len <= 1) + return L""; + + wstring dst; + dst.resize(len); + MultiByteToWideChar(CP_UTF8, 0, src, len, dst.data(), len); + return dst; +} + wstring stow(const string& src) { int len = MultiByteToWideChar(CP_UTF8, 0, src.c_str(), int(src.length()), nullptr, 0); if (len <= 0) diff --git a/src/utils/utils.h b/src/utils/utils.h index 8f493b44..56046f28 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -103,32 +103,30 @@ vector getAvailibleRenderers(); struct Rect : SDL_Rect { Rect() = default; - Rect(int n); - Rect(int x, int y, int w, int h); - Rect(const vec2i& pos, const vec2i& size); + constexpr Rect(int n); + constexpr Rect(int x, int y, int w, int h); + constexpr Rect(const vec2i& pos, const vec2i& size); vec2i& pos(); - const vec2i& pos() const; + constexpr vec2i pos() const; vec2i& size(); - const vec2i& size() const; - vec2i end() const; - vec2i back() const; - - bool overlap(const vec2i& point) const; - bool overlap(const Rect& rect, vec2i& sback, vec2i& rback) const; - Rect crop(const Rect& frame); // crop rect so it fits in the frame (aka set rect to the area where they overlap) and return how much was cut off - Rect getOverlap(const Rect& frame) const; // same as above except it returns the overlap instead of the crop and it doesn't modify the rect + constexpr vec2i size() const; + constexpr vec2i end() const; + + bool contain(const vec2i& point) const; + Rect crop(const Rect& frame); // crop rect so it fits in the frame (aka set rect to the area where they overlap) and return how much was cut off + Rect intersect(const Rect& rect) const; // same as above except it returns the overlap instead of the crop and it doesn't modify itself }; -inline Rect::Rect(int n) : +inline constexpr Rect::Rect(int n) : SDL_Rect({n, n, n, n}) {} -inline Rect::Rect(int x, int y, int w, int h) : +inline constexpr Rect::Rect(int x, int y, int w, int h) : SDL_Rect({x, y, w, h}) {} -inline Rect::Rect(const vec2i& pos, const vec2i& size) : +inline constexpr Rect::Rect(const vec2i& pos, const vec2i& size) : SDL_Rect({pos.x, pos.y, size.w, size.h}) {} @@ -136,28 +134,29 @@ inline vec2i& Rect::pos() { return *reinterpret_cast(this); } -inline const vec2i& Rect::pos() const { - return *reinterpret_cast(this); +inline constexpr vec2i Rect::pos() const { + return vec2i(x, y); } inline vec2i& Rect::size() { return reinterpret_cast(this)[1]; } -inline const vec2i& Rect::size() const { - return reinterpret_cast(this)[1]; +inline constexpr vec2i Rect::size() const { + return vec2i(w, h); } -inline vec2i Rect::end() const { +inline constexpr vec2i Rect::end() const { return pos() + size(); } -inline vec2i Rect::back() const { - return end() - 1; +inline bool Rect::contain(const vec2i& point) const { + return SDL_PointInRect(reinterpret_cast(&point), this); } -inline bool Rect::overlap(const vec2i& point) const { - return point.x >= x && point.x < x + w && point.y >= y && point.y < y + h; +inline Rect Rect::intersect(const Rect& rect) const { + Rect isct; + return SDL_IntersectRect(this, &rect, &isct) ? isct : Rect(0); } // SDL_Texture wrapper @@ -343,6 +342,7 @@ vec2 clampLow(const vec2& val, const vec2& min) { #ifdef _WIN32 string wtos(const wchar* wstr); string wtos(const wstring& wstr); +wstring stow(const char* str); wstring stow(const string& str); #endif inline bool stob(const string& str) { diff --git a/src/utils/vec2.h b/src/utils/vec2.h index 45767572..1bf9ec11 100644 --- a/src/utils/vec2.h +++ b/src/utils/vec2.h @@ -302,7 +302,7 @@ constexpr vec2 operator/(const vec2& a, const T& b) { template constexpr vec2 operator/(const T& a, const vec2& b) { - return vec2(a % b.x, a % b.y); + return vec2(a / b.x, a / b.y); } template diff --git a/src/utils/widgets.cpp b/src/utils/widgets.cpp index 514946e2..faa5fa16 100644 --- a/src/utils/widgets.cpp +++ b/src/utils/widgets.cpp @@ -207,6 +207,10 @@ void Label::drawSelf() const { World::drawSys()->drawLabel(this); } +void Label::onResize() { + updateTextTex(); +} + void Label::postInit() { updateTextTex(); } @@ -219,7 +223,7 @@ void Label::setText(const string& str) { Rect Label::textFrame() const { Rect rct = rect(); int ofs = textIconOffset(); - return Rect(rct.x + ofs + textMargin, rct.y, rct.w - ofs - textMargin * 2, rct.h).getOverlap(frame()); + return Rect(rct.x + ofs + textMargin, rct.y, rct.w - ofs - textMargin * 2, rct.h).intersect(frame()); } Rect Label::texRect() const { diff --git a/src/utils/widgets.h b/src/utils/widgets.h index 206ddc39..783a93dd 100644 --- a/src/utils/widgets.h +++ b/src/utils/widgets.h @@ -254,6 +254,7 @@ class Label : public Button { virtual ~Label() override; virtual void drawSelf() const override; + virtual void onResize() override; virtual void postInit() override; const string& getText() const;