diff --git a/SourceX/DiabloUI/art_draw.cpp b/SourceX/DiabloUI/art_draw.cpp index 6c8e06b21..13b07a464 100644 --- a/SourceX/DiabloUI/art_draw.cpp +++ b/SourceX/DiabloUI/art_draw.cpp @@ -11,12 +11,12 @@ void DrawArt(int screenX, int screenY, Art *art, int nFrame, Uint16 srcW, Uint16 if (screenY >= SCREEN_HEIGHT || screenX >= SCREEN_WIDTH || art->surface == NULL) return; - SDL_Rect src_rect = { - 0, - static_cast(nFrame * art->h()), - static_cast(art->w()), - static_cast(art->h()) - }; + SDL_Rect src_rect; + src_rect.x = 0; + src_rect.y = nFrame * art->h(); + src_rect.w = art->w(); + src_rect.h = art->h(); + ScaleOutputRect(&src_rect); if (srcW && srcW < src_rect.w) @@ -36,7 +36,8 @@ void DrawArt(int screenX, int screenY, Art *art, int nFrame, Uint16 srcW, Uint16 ErrSdl(); } -void DrawAnimatedArt(Art *art, int screenX, int screenY) { +void DrawAnimatedArt(Art *art, int screenX, int screenY) +{ DrawArt(screenX, screenY, art, GetAnimationFrame(art->frames)); } diff --git a/SourceX/DiabloUI/button.cpp b/SourceX/DiabloUI/button.cpp index d228f5557..65b5d0f6f 100644 --- a/SourceX/DiabloUI/button.cpp +++ b/SourceX/DiabloUI/button.cpp @@ -16,18 +16,21 @@ void LoadSmlButtonArt() void RenderButton(UiButton *button) { int frame; - if (button->pressed) { + if (button->m_pressed) { frame = UiButton::PRESSED; } else { frame = UiButton::DEFAULT; } - DrawArt(button->rect.x, button->rect.y, button->art, frame, button->rect.w, button->rect.h); + DrawArt(button->m_rect.x, button->m_rect.y, button->m_art, frame, button->m_rect.w, button->m_rect.h); - SDL_Rect text_rect = button->rect; - if (!button->pressed) + SDL_Rect text_rect = button->m_rect; + if (!button->m_pressed) --text_rect.y; - DrawTTF(button->text, text_rect, UIS_CENTER, - SDL_Color { 243, 243, 243, 0 }, SDL_Color { 0, 0, 0, 0 }, &button->render_cache); + + SDL_Color color1 = { 243, 243, 243, 0 }; + SDL_Color color2 = { 0, 0, 0, 0 }; + DrawTTF(button->m_text, text_rect, UIS_CENTER, + color1, color2, &button->m_render_cache); } bool HandleMouseEventButton(const SDL_Event &event, UiButton *button) @@ -36,10 +39,10 @@ bool HandleMouseEventButton(const SDL_Event &event, UiButton *button) return false; switch (event.type) { case SDL_MOUSEBUTTONUP: - button->action(); + button->m_action(); return true; case SDL_MOUSEBUTTONDOWN: - button->pressed = true; + button->m_pressed = true; return true; default: return false; @@ -48,7 +51,7 @@ bool HandleMouseEventButton(const SDL_Event &event, UiButton *button) void HandleGlobalMouseUpButton(UiButton *button) { - button->pressed = false; + button->m_pressed = false; } } // namespace dvl diff --git a/SourceX/DiabloUI/button.h b/SourceX/DiabloUI/button.h index e1412b7c8..80b55c905 100644 --- a/SourceX/DiabloUI/button.h +++ b/SourceX/DiabloUI/button.h @@ -14,17 +14,6 @@ inline void UnloadSmlButtonArt() const Uint16 SML_BUTTON_WIDTH = 110; const Uint16 SML_BUTTON_HEIGHT = 28; -constexpr UiButton MakeSmlButton( - const char *text, void (*action)(), Sint16 x, Sint16 y, int flags = 0) -{ - return UiButton( - &SmlButton, - text, - action, - SDL_Rect{ x, y, SML_BUTTON_WIDTH, SML_BUTTON_HEIGHT }, - flags); -} - void RenderButton(UiButton *button); bool HandleMouseEventButton(const SDL_Event &event, UiButton *button); void HandleGlobalMouseUpButton(UiButton *button); diff --git a/SourceX/DiabloUI/credits.cpp b/SourceX/DiabloUI/credits.cpp index b1265ad3e..bbffc5bd5 100644 --- a/SourceX/DiabloUI/credits.cpp +++ b/SourceX/DiabloUI/credits.cpp @@ -33,31 +33,26 @@ struct SurfaceDeleter { } }; -using SurfacePtr = std::unique_ptr; - struct CachedLine { - CachedLine() = default; - - explicit CachedLine(std::size_t index, SurfacePtr surface) - : index(index) - , surface(std::move(surface)) - , palette_version(pal_surface_palette_version) + CachedLine(std::size_t index, SDL_Surface *surface) { + m_index = index; + m_surface = surface; } - std::size_t index; - SurfacePtr surface; + std::size_t m_index; + SDL_Surface *m_surface; unsigned int palette_version; }; -SurfacePtr RenderText(const char *text, SDL_Color color) +SDL_Surface *RenderText(const char *text, SDL_Color color) { if (text[0] == '\0') return NULL; SDL_Surface *result = TTF_RenderUTF8_Solid(font, text, color); if (result == NULL) SDL_Log(TTF_GetError()); - return SurfacePtr(result); + return result; } CachedLine PrepareLine(std::size_t index) @@ -67,41 +62,40 @@ CachedLine PrepareLine(std::size_t index) ++contents; const SDL_Color shadow_color = { 0, 0, 0, 0 }; - auto text = RenderText(contents, shadow_color); + SDL_Surface *text = RenderText(contents, shadow_color); // Precompose shadow and text: - SurfacePtr surface; + SDL_Surface *surface = NULL; if (text != NULL) { // Set up the target surface to have 3 colors: mask, text, and shadow. - surface.reset( - SDL_CreateRGBSurfaceWithFormat(0, text->w + SHADOW_OFFSET_X, text->h + SHADOW_OFFSET_Y, 8, SDL_PIXELFORMAT_INDEX8)); - const SDL_Color &mask_color = { 0, 255, 0, 0 }; // Any color different from both shadow and text + surface = SDL_CreateRGBSurfaceWithFormat(0, text->w + SHADOW_OFFSET_X, text->h + SHADOW_OFFSET_Y, 8, SDL_PIXELFORMAT_INDEX8); + const SDL_Color mask_color = { 0, 255, 0, 0 }; // Any color different from both shadow and text const SDL_Color &text_color = palette->colors[224]; SDL_Color colors[3] = { mask_color, text_color, shadow_color }; - if (SDLC_SetSurfaceColors(surface.get(), colors, 0, 3) <= -1) + if (SDLC_SetSurfaceColors(surface, colors, 0, 3) <= -1) SDL_Log(SDL_GetError()); - SDLC_SetColorKey(surface.get(), 0); + SDLC_SetColorKey(surface, 0); // Blit the shadow first: SDL_Rect shadow_rect = { SHADOW_OFFSET_X, SHADOW_OFFSET_Y, 0, 0 }; - if (SDL_BlitSurface(text.get(), NULL, surface.get(), &shadow_rect) <= -1) + if (SDL_BlitSurface(text, NULL, surface, &shadow_rect) <= -1) ErrSdl(); // Change the text surface color and blit again: SDL_Color text_colors[2] = { mask_color, text_color }; - if (SDLC_SetSurfaceColors(text.get(), text_colors, 0, 2) <= -1) + if (SDLC_SetSurfaceColors(text, text_colors, 0, 2) <= -1) ErrSdl(); - SDLC_SetColorKey(text.get(), 0); + SDLC_SetColorKey(text, 0); - if (SDL_BlitSurface(text.get(), NULL, surface.get(), NULL) <= -1) + if (SDL_BlitSurface(text, NULL, surface, NULL) <= -1) ErrSdl(); - SDL_Surface *surface_ptr = surface.release(); + SDL_Surface *surface_ptr = surface; ScaleSurfaceToOutput(&surface_ptr); - surface.reset(surface_ptr); + surface = surface_ptr; } - return CachedLine(index, std::move(surface)); + return CachedLine(index, surface); } /** @@ -154,10 +148,10 @@ public: empty_ = true; } - void push_back(CachedLine &&line) + void push_back(CachedLine line) { end_ = (end_ + 1) % data_.size(); - data_[end_] = std::move(line); + data_[end_] = line; empty_ = false; } @@ -222,12 +216,12 @@ void CreditsRenderer::Render() return; } - while (!lines_.empty() && lines_.front().index != lines_begin) + while (!lines_.empty() && lines_.front().m_index != lines_begin) lines_.pop_front(); if (lines_.empty()) lines_.push_back(PrepareLine(lines_begin)); - while (lines_.back().index + 1 != lines_end) - lines_.push_back(PrepareLine(lines_.back().index + 1)); + while (lines_.back().m_index + 1 != lines_end) + lines_.push_back(PrepareLine(lines_.back().m_index + 1)); SDL_Rect viewport = VIEWPORT; ScaleOutputRect(&viewport); @@ -236,23 +230,23 @@ void CreditsRenderer::Render() // We use unscaled coordinates for calculation throughout. Sint16 dest_y = VIEWPORT.y - (offset_y - lines_begin * LINE_H); for (std::size_t i = 0; i < lines_.size(); ++i, dest_y += LINE_H) { - auto &line = lines_[i]; - if (line.surface == NULL) + CachedLine &line = lines_[i]; + if (line.m_surface == NULL) continue; // Still fading in: the cached line was drawn with a different fade level. if (line.palette_version != pal_surface_palette_version) - line = PrepareLine(line.index); + line = PrepareLine(line.m_index); Sint16 dest_x = PANEL_LEFT + VIEWPORT.x + 31; - if (CREDITS_LINES[line.index][0] == '\t') + if (CREDITS_LINES[line.m_index][0] == '\t') dest_x += 40; SDL_Rect dst_rect = { dest_x, dest_y, 0, 0 }; ScaleOutputRect(&dst_rect); - dst_rect.w = line.surface.get()->w; - dst_rect.h = line.surface.get()->h; - if (SDL_BlitSurface(line.surface.get(), NULL, GetOutputSurface(), &dst_rect) < 0) + dst_rect.w = line.m_surface->w; + dst_rect.h = line.m_surface->h; + if (SDL_BlitSurface(line.m_surface, NULL, GetOutputSurface(), &dst_rect) < 0) ErrSdl(); } SDL_SetClipRect(GetOutputSurface(), NULL); diff --git a/SourceX/DiabloUI/diabloui.cpp b/SourceX/DiabloUI/diabloui.cpp index 2570623d1..f675b02e8 100644 --- a/SourceX/DiabloUI/diabloui.cpp +++ b/SourceX/DiabloUI/diabloui.cpp @@ -42,8 +42,7 @@ void (*gfnListFocus)(int value); void (*gfnListSelect)(int value); void (*gfnListEsc)(); bool (*gfnListYesNo)(); -UiItem *gUiItems; -int gUiItemCnt; +std::vector gUiItems; bool UiItemsWraps; char *UiTextInput; int UiTextInputLen; @@ -75,7 +74,7 @@ void UiDestroy() UnloadArtFonts(); } -void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), UiItem *items, int itemCnt, bool itemsWraps, bool (*fnYesNo)()) +void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), std::vector items, bool itemsWraps, bool (*fnYesNo)()) { SelectedItem = min; SelectedItemMin = min; @@ -86,20 +85,21 @@ void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(i gfnListEsc = fnEsc; gfnListYesNo = fnYesNo; gUiItems = items; - gUiItemCnt = itemCnt; UiItemsWraps = itemsWraps; if (fnFocus) fnFocus(min); SDL_StopTextInput(); // input is enabled by default - for (int i = 0; i < itemCnt; i++) { - if (items[i].type == UI_EDIT) { + for (std::size_t i = 0; i < items.size(); i++) { + if (items[i]->m_type == UI_EDIT) { + UiEdit *pItemUIEdit = (UiEdit *)items[i]; #ifdef __SWITCH__ - switch_start_text_input(items[i - 1].art_text.text, items[i].edit.value, /*multiline=*/0); + switch_start_text_input("", pItemUIEdit->m_value, pItemUIEdit->m_max_length, /*multiline=*/0); #endif + SDL_StartTextInput(); - UiTextInput = items[i].edit.value; - UiTextInputLen = items[i].edit.max_length; + UiTextInput = pItemUIEdit->m_value; + UiTextInputLen = pItemUIEdit->m_max_length; } } } @@ -115,6 +115,20 @@ void UiInitScrollBar(UiScrollBar *ui_sb, std::size_t viewport_size, const std::s } } +void UiInitList_clear() +{ + SelectedItem = 0; + SelectedItemMin = 1; + SelectedItemMax = 1; + ListViewportSize = 1; + gfnListFocus = NULL; + gfnListSelect = NULL; + gfnListEsc = NULL; + gfnListYesNo = NULL; + gUiItems.clear(); + UiItemsWraps = false; +} + void UiPlayMoveSound() { if (gfnSoundFunction) @@ -309,7 +323,7 @@ void UiFocusNavigation(SDL_Event *event) } if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) { - if (UiItemMouseEvents(event, gUiItems, gUiItemCnt)) + if (UiItemMouseEvents(event, gUiItems)) return; } } @@ -580,6 +594,18 @@ void LoadBackgroundArt(const char *pszFile) RenderPresent(); } +void UiAddBackground(std::vector *vecDialog) +{ + SDL_Rect rect = { PANEL_LEFT, 0, 640, 480 }; + vecDialog->push_back(new UiImage(&ArtBackground, rect)); +} + +void UiAddLogo(std::vector *vecDialog, int size, int height) +{ + SDL_Rect rect = { 0, height, 0, 0 }; + vecDialog->push_back(new UiImage(&ArtLogos[size], /*animated=*/true, /*frame=*/0, rect, UIS_CENTER)); +} + void UiFadeIn() { if (fadeValue < 256) { @@ -625,7 +651,7 @@ void UiPollAndRender() UiFocusNavigation(&event); UiHandleEvents(&event); } - UiRenderItems(gUiItems, gUiItemCnt); + UiRenderItems(gUiItems); DrawMouse(); UiFadeIn(); } @@ -634,58 +660,58 @@ namespace { void Render(UiText *ui_text) { - DrawTTF(ui_text->text, - ui_text->rect, - ui_text->flags, - ui_text->color, - ui_text->shadow_color, - &ui_text->render_cache); + DrawTTF(ui_text->m_text, + ui_text->m_rect, + ui_text->m_iFlags, + ui_text->m_color, + ui_text->m_shadow_color, + &ui_text->m_render_cache); } -void Render(const UiArtText &ui_art_text) +void Render(const UiArtText *ui_art_text) { - DrawArtStr(ui_art_text.text, ui_art_text.rect, ui_art_text.flags); + DrawArtStr(ui_art_text->m_text, ui_art_text->m_rect, ui_art_text->m_iFlags); } -void Render(const UiImage &ui_image) +void Render(const UiImage *ui_image) { - int x = ui_image.rect.x; - if ((ui_image.flags & UIS_CENTER) && ui_image.art != NULL) { - const int x_offset = GetCenterOffset(ui_image.art->w(), ui_image.rect.w); + int x = ui_image->m_rect.x; + if ((ui_image->m_iFlags & UIS_CENTER) && ui_image->m_art != NULL) { + const int x_offset = GetCenterOffset(ui_image->m_art->w(), ui_image->m_rect.w); x += x_offset; } - if (ui_image.animated) { - DrawAnimatedArt(ui_image.art, x, ui_image.rect.y); + if (ui_image->m_animated) { + DrawAnimatedArt(ui_image->m_art, x, ui_image->m_rect.y); } else { - DrawArt(x, ui_image.rect.y, ui_image.art, ui_image.frame, ui_image.rect.w); + DrawArt(x, ui_image->m_rect.y, ui_image->m_art, ui_image->m_frame, ui_image->m_rect.w); } } -void Render(const UiArtTextButton &ui_button) +void Render(const UiArtTextButton *ui_button) { - DrawArtStr(ui_button.text, ui_button.rect, ui_button.flags); + DrawArtStr(ui_button->m_text, ui_button->m_rect, ui_button->m_iFlags); } -void Render(const UiList &ui_list) +void Render(const UiList *ui_list) { - for (std::size_t i = 0; i < ui_list.length; ++i) { - SDL_Rect rect = ui_list.itemRect(i); - const auto &item = ui_list.items[i]; - if (item.value == SelectedItem) + for (std::size_t i = 0; i < ui_list->m_vecItems.size(); ++i) { + SDL_Rect rect = ui_list->itemRect(i); + const UiListItem *item = ui_list->GetItem(i); + if (item->m_value == SelectedItem) DrawSelector(rect); - DrawArtStr(item.text, rect, ui_list.flags); + DrawArtStr(item->m_text, rect, ui_list->m_iFlags); } } -void Render(const UiScrollBar &ui_sb) +void Render(const UiScrollBar *ui_sb) { // Bar background (tiled): { const std::size_t bg_y_end = DownArrowRect(ui_sb).y; - std::size_t bg_y = ui_sb.rect.y + ui_sb.arrow->h(); + std::size_t bg_y = ui_sb->m_rect.y + ui_sb->m_arrow->h(); while (bg_y < bg_y_end) { - std::size_t drawH = std::min(bg_y + ui_sb.bg->h(), bg_y_end) - bg_y; - DrawArt(ui_sb.rect.x, bg_y, ui_sb.bg, 0, SCROLLBAR_BG_WIDTH, drawH); + std::size_t drawH = std::min(bg_y + ui_sb->m_bg->h(), bg_y_end) - bg_y; + DrawArt(ui_sb->m_rect.x, bg_y, ui_sb->m_bg, 0, SCROLLBAR_BG_WIDTH, drawH); bg_y += drawH; } } @@ -694,91 +720,94 @@ void Render(const UiScrollBar &ui_sb) { const SDL_Rect rect = UpArrowRect(ui_sb); const int frame = static_cast(scrollBarState.upArrowPressed ? ScrollBarArrowFrame_UP_ACTIVE : ScrollBarArrowFrame_UP); - DrawArt(rect.x, rect.y, ui_sb.arrow, frame, rect.w); + DrawArt(rect.x, rect.y, ui_sb->m_arrow, frame, rect.w); } { const SDL_Rect rect = DownArrowRect(ui_sb); const int frame = static_cast(scrollBarState.downArrowPressed ? ScrollBarArrowFrame_DOWN_ACTIVE : ScrollBarArrowFrame_DOWN); - DrawArt(rect.x, rect.y, ui_sb.arrow, frame, rect.w); + DrawArt(rect.x, rect.y, ui_sb->m_arrow, frame, rect.w); } // Thumb: - { + if (SelectedItemMax - SelectedItemMin > 0) { const SDL_Rect rect = ThumbRect( ui_sb, SelectedItem - SelectedItemMin, SelectedItemMax - SelectedItemMin + 1); - DrawArt(rect.x, rect.y, ui_sb.thumb); + DrawArt(rect.x, rect.y, ui_sb->m_thumb); } } -void Render(const UiEdit &ui_edit) +void Render(const UiEdit *ui_edit) { - DrawSelector(ui_edit.rect); - SDL_Rect rect = ui_edit.rect; + DrawSelector(ui_edit->m_rect); + SDL_Rect rect = ui_edit->m_rect; rect.x += 43; rect.y += 1; rect.w -= 86; - DrawArtStr(ui_edit.value, rect, ui_edit.flags, /*drawTextCursor=*/true); + DrawArtStr(ui_edit->m_value, rect, ui_edit->m_iFlags, /*drawTextCursor=*/true); } -void RenderItem(UiItem *item) +void RenderItem(UiItemBase *item) { if (item->has_flag(UIS_HIDDEN)) return; - switch (item->type) { + switch (item->m_type) { case UI_TEXT: - Render(&item->text); + Render(static_cast(item)); break; case UI_ART_TEXT: - Render(item->art_text); + Render(static_cast(item)); break; case UI_IMAGE: - Render(item->image); + Render(static_cast(item)); break; case UI_ART_TEXT_BUTTON: - Render(item->art_text_button); + Render(static_cast(item)); break; case UI_BUTTON: - RenderButton(&item->button); + RenderButton(static_cast(item)); break; case UI_LIST: - Render(item->list); + Render(static_cast(item)); break; case UI_SCROLLBAR: - Render(item->scrollbar); + Render(static_cast(item)); break; case UI_EDIT: - Render(item->edit); + Render(static_cast(item)); break; } } -bool HandleMouseEventArtTextButton(const SDL_Event &event, const UiArtTextButton &ui_button) +bool HandleMouseEventArtTextButton(const SDL_Event &event, const UiArtTextButton *ui_button) { if (event.type != SDL_MOUSEBUTTONDOWN || event.button.button != SDL_BUTTON_LEFT) return false; - ui_button.action(); + ui_button->m_action(); return true; } -bool HandleMouseEventList(const SDL_Event &event, const UiList &ui_list) +bool HandleMouseEventList(const SDL_Event &event, UiList *ui_list) { if (event.type != SDL_MOUSEBUTTONDOWN || event.button.button != SDL_BUTTON_LEFT) return false; - const UiListItem *list_item = ui_list.itemAt(event.button.y); - if (gfnListFocus != NULL && SelectedItem != list_item->value) { - UiFocus(list_item->value); + + const UiListItem *list_item = ui_list->itemAt(event.button.y); + + if (gfnListFocus != NULL && SelectedItem != list_item->m_value) { + UiFocus(list_item->m_value); #ifdef USE_SDL1 } else if (gfnListFocus == NULL) { #else } else if (gfnListFocus == NULL || event.button.clicks >= 2) { #endif - SelectedItem = list_item->value; + SelectedItem = list_item->m_value; UiFocusNavigationSelect(); } + return true; } -bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollBar &ui_sb) +bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollBar *ui_sb) { if (event.button.button != SDL_BUTTON_LEFT) return false; @@ -812,19 +841,19 @@ bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollBar &ui_sb) return false; } -bool HandleMouseEvent(const SDL_Event &event, UiItem *item) +bool HandleMouseEvent(const SDL_Event &event, UiItemBase *item) { - if (item->has_any_flag(UIS_HIDDEN | UIS_DISABLED) || !IsInsideRect(event, item->rect())) + if (item->has_any_flag(UIS_HIDDEN | UIS_DISABLED) || !IsInsideRect(event, item->m_rect)) return false; - switch (item->type) { + switch (item->m_type) { case UI_ART_TEXT_BUTTON: - return HandleMouseEventArtTextButton(event, item->art_text_button); + return HandleMouseEventArtTextButton(event, (UiArtTextButton *)item); case UI_BUTTON: - return HandleMouseEventButton(event, &item->button); + return HandleMouseEventButton(event, (UiButton *)item); case UI_LIST: - return HandleMouseEventList(event, item->list); + return HandleMouseEventList(event, (UiList *)item); case UI_SCROLLBAR: - return HandleMouseEventScrollBar(event, item->scrollbar); + return HandleMouseEventScrollBar(event, (UiScrollBar *)item); default: return false; } @@ -839,16 +868,17 @@ void LoadPalInMem(const SDL_Color *pPal) } } -void UiRenderItems(UiItem *items, std::size_t size) +void UiRenderItems(std::vector items) { - for (std::size_t i = 0; i < size; i++) - RenderItem(&items[i]); + for (std::size_t i = 0; i < items.size(); i++) + RenderItem((UiItemBase *)items[i]); } -bool UiItemMouseEvents(SDL_Event *event, UiItem *items, std::size_t size) +bool UiItemMouseEvents(SDL_Event *event, std::vector items) { - if (!items || size == 0) + if (items.size() == 0) { return false; + } // In SDL2 mouse events already use logical coordinates. #ifdef USE_SDL1 @@ -856,8 +886,8 @@ bool UiItemMouseEvents(SDL_Event *event, UiItem *items, std::size_t size) #endif bool handled = false; - for (std::size_t i = 0; i < size; i++) { - if (HandleMouseEvent(*event, &items[i])) { + for (std::size_t i = 0; i < items.size(); i++) { + if (HandleMouseEvent(*event, items[i])) { handled = true; break; } @@ -865,10 +895,10 @@ bool UiItemMouseEvents(SDL_Event *event, UiItem *items, std::size_t size) if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_LEFT) { scrollBarState.downArrowPressed = scrollBarState.upArrowPressed = false; - for (std::size_t i = 0; i < size; ++i) { - UiItem &item = items[i]; - if (item.type == UI_BUTTON) - HandleGlobalMouseUpButton(&item.button); + for (std::size_t i = 0; i < items.size(); ++i) { + UiItemBase *&item = items[i]; + if (item->m_type == UI_BUTTON) + HandleGlobalMouseUpButton((UiButton *)item); } } diff --git a/SourceX/DiabloUI/diabloui.h b/SourceX/DiabloUI/diabloui.h index 543b50c2c..4c60795d6 100644 --- a/SourceX/DiabloUI/diabloui.h +++ b/SourceX/DiabloUI/diabloui.h @@ -29,36 +29,27 @@ extern Art ArtCursor; extern Art ArtHero; extern bool gbSpawned; -constexpr auto MAINMENU_BACKGROUND = UiImage(&ArtBackground, { PANEL_LEFT, 0, 640, 480 }); -constexpr auto MAINMENU_LOGO = UiImage(&ArtLogos[LOGO_MED], /*animated=*/true, /*frame=*/0, { 0, 0, 0, 0 }, UIS_CENTER); - -template -constexpr size_t size(T (&)[N]) -{ - return N; -} - extern void (*gfnSoundFunction)(char *file); extern BOOL (*gfnHeroInfo)(BOOL (*fninfofunc)(_uiheroinfo *)); -bool IsInsideRect(const SDL_Event &event, const SDL_Rect &rect); void UiFadeIn(); -void UiFocusNavigation(SDL_Event *event); void UiHandleEvents(SDL_Event *event); -bool UiItemMouseEvents(SDL_Event *event, UiItem *items, std::size_t size); +bool UiItemMouseEvents(SDL_Event *event, std::vector items); int GetCenterOffset(int w, int bw = 0); void LoadPalInMem(const SDL_Color *pPal); void DrawMouse(); void LoadBackgroundArt(const char *pszFile); -void SetMenu(int MenuId); +void UiAddBackground(std::vector *vecDialog); +void UiAddLogo(std::vector *vecDialog, int size = LOGO_MED, int height = 0); void UiFocusNavigationSelect(); void UiFocusNavigationEsc(); void UiFocusNavigationYesNo(); -void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), UiItem *items, int size, bool wraps = false, bool (*fnYesNo)() = NULL); +void UiInitList(int min, int max, void (*fnFocus)(int value), void (*fnSelect)(int value), void (*fnEsc)(), std::vector items, bool wraps = false, bool (*fnYesNo)() = NULL); void UiInitScrollBar(UiScrollBar *ui_sb, std::size_t viewport_size, const std::size_t *current_offset); void UiClearScreen(); void UiPollAndRender(); -void UiRenderItems(UiItem *items, std::size_t size); +void UiRenderItems(std::vector items); +void UiInitList_clear(); void DvlIntSetting(const char *valuename, int *value); void DvlStringSetting(const char *valuename, char *string, int len); diff --git a/SourceX/DiabloUI/dialogs.cpp b/SourceX/DiabloUI/dialogs.cpp index c679c1c07..603053d18 100644 --- a/SourceX/DiabloUI/dialogs.cpp +++ b/SourceX/DiabloUI/dialogs.cpp @@ -17,14 +17,9 @@ extern SDL_Surface *pal_surface; namespace { Art dialogArt; -char dialogText[256]; -char dialogCaption[1024]; bool fontWasLoaded; bool textInputWasActive; -UiItem *dialogItems; -std::size_t dialogItemsSize; - bool dialogEnd; void DialogActionOK() @@ -32,20 +27,8 @@ void DialogActionOK() dialogEnd = true; } -const auto DIALOG_ART_L = UiImage(&dialogArt, { PANEL_LEFT + 127, 100, 385, 280 }); - -UiItem OK_DIALOG[] = { - UiImage(&dialogArt, { PANEL_LEFT + 180, 168, 280, 144 }), - UiText(dialogText, { PANEL_LEFT + 200, 211, 240, 80 }, UIS_CENTER), - MakeSmlButton("OK", &DialogActionOK, PANEL_LEFT + 265, 265), -}; - -UiItem OK_DIALOG_WITH_CAPTION[] = { - DIALOG_ART_L, - UiText(dialogText, SDL_Color{ 255, 255, 0, 0 }, { PANEL_LEFT + 147, 110, 345, 20 }, UIS_CENTER), - UiText(dialogCaption, { PANEL_LEFT + 147, 141, 345, 190 }, UIS_CENTER), - MakeSmlButton("OK", &DialogActionOK, PANEL_LEFT + 264, 335), -}; +std::vector vecNULL; +std::vector vecOkDialog; // clang-format off #define BLANKCOLOR { 0, 0xFF, 0, 0 } @@ -176,7 +159,30 @@ void LoadFallbackPalette() void Init(const char *text, const char *caption, bool error, bool renderBehind) { - strcpy(dialogText, text); + if (caption == NULL) { + SDL_Rect rect1 = { PANEL_LEFT + 180, 168, 280, 144 }; + vecOkDialog.push_back(new UiImage(&dialogArt, rect1)); + + SDL_Rect rect2 = { PANEL_LEFT + 200, 211, 240, 80 }; + vecOkDialog.push_back(new UiText(text, rect2, UIS_CENTER)); + + SDL_Rect rect3 = { PANEL_LEFT + 265, 265, SML_BUTTON_WIDTH, SML_BUTTON_HEIGHT }; + vecOkDialog.push_back(new UiButton(&SmlButton, "OK", &DialogActionOK, rect3, 0)); + } else { + SDL_Rect rect1 = { PANEL_LEFT + 127, 100, 385, 280 }; + vecOkDialog.push_back(new UiImage(&dialogArt, rect1)); + + SDL_Color color = { 255, 255, 0, 0 }; + SDL_Rect rect2 = { PANEL_LEFT + 147, 110, 345, 20 }; + vecOkDialog.push_back(new UiText(text, color, rect2, UIS_CENTER)); + + SDL_Rect rect3 = { PANEL_LEFT + 147, 141, 345, 190 }; + vecOkDialog.push_back(new UiText(caption, rect3, UIS_CENTER)); + + SDL_Rect rect4 = { PANEL_LEFT + 264, 335, SML_BUTTON_WIDTH, SML_BUTTON_HEIGHT }; + vecOkDialog.push_back(new UiButton(&SmlButton, "OK", &DialogActionOK, rect4, 0)); + } + if (!renderBehind) { LoadBackgroundArt("ui_art\\black.pcx"); if (ArtBackground.surface == NULL) { @@ -186,17 +192,12 @@ void Init(const char *text, const char *caption, bool error, bool renderBehind) SetFadeLevel(256); if (caption == NULL) { LoadMaskedArt(error ? "ui_art\\srpopup.pcx" : "ui_art\\spopup.pcx", &dialogArt); - dialogItems = OK_DIALOG; - dialogItemsSize = size(OK_DIALOG); } else { if (error) { - LoadArt(&dialogArt, popupData, DIALOG_ART_L.rect.w, DIALOG_ART_L.rect.h); + LoadArt(&dialogArt, popupData, 385, 280); } else { LoadMaskedArt("ui_art\\lpopup.pcx", &dialogArt); } - strcpy(dialogCaption, caption); - dialogItems = OK_DIALOG_WITH_CAPTION; - dialogItemsSize = size(OK_DIALOG_WITH_CAPTION); } LoadSmlButtonArt(); @@ -215,12 +216,15 @@ void Deinit() UnloadTtfFont(); if (textInputWasActive) SDL_StartTextInput(); - for (std::size_t i = 0; i < dialogItemsSize; ++i) { - dialogItems[i].FreeCache(); + + for (std::size_t i = 0; i < vecOkDialog.size(); i++) { + UiItemBase *pUIItem = vecOkDialog[i]; + delete pUIItem; } + vecOkDialog.clear(); } -void DialogLoop(UiItem *items, std::size_t num_items, UiItem *renderBehind, std::size_t renderBehind_size) +void DialogLoop(std::vector items, std::vector renderBehind) { SDL_Event event; dialogEnd = false; @@ -229,7 +233,7 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *renderBehind, std: switch (event.type) { case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: - UiItemMouseEvents(&event, items, num_items); + UiItemMouseEvents(&event, items); break; default: switch (GetMenuAction(event)) { @@ -245,12 +249,12 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *renderBehind, std: UiHandleEvents(&event); } - if (renderBehind_size == 0) { + if (renderBehind.size() == 0) { SDL_FillRect(GetOutputSurface(), NULL, 0); } else { - UiRenderItems(renderBehind, renderBehind_size); + UiRenderItems(renderBehind); } - UiRenderItems(items, num_items); + UiRenderItems(items); DrawMouse(); UiFadeIn(); } while (!dialogEnd); @@ -258,7 +262,7 @@ void DialogLoop(UiItem *items, std::size_t num_items, UiItem *renderBehind, std: } // namespace -void UiOkDialog(const char *text, const char *caption, bool error, UiItem *renderBehind, std::size_t renderBehind_size) +void UiOkDialog(const char *text, const char *caption, bool error, std::vector renderBehind) { static bool inDialog = false; @@ -279,25 +283,25 @@ void UiOkDialog(const char *text, const char *caption, bool error, UiItem *rende } inDialog = true; - Init(text, caption, error, renderBehind_size > 0); - DialogLoop(dialogItems, dialogItemsSize, renderBehind, renderBehind_size); + Init(text, caption, error, renderBehind.size() > 0); + DialogLoop(vecOkDialog, renderBehind); Deinit(); inDialog = false; } -void UiErrorOkDialog(const char *text, const char *caption, UiItem *renderBehind, std::size_t renderBehind_size) +void UiErrorOkDialog(const char *text, const char *caption, std::vector renderBehind) { - UiOkDialog(text, caption, /*error=*/true, renderBehind, renderBehind_size); + UiOkDialog(text, caption, /*error=*/true, renderBehind); } void UiErrorOkDialog(const char *text, const char *caption, bool error) { - UiOkDialog(text, caption, error, NULL, 0); + UiOkDialog(text, caption, error, vecNULL); } -void UiErrorOkDialog(const char *text, UiItem *renderBehind, std::size_t renderBehind_size) +void UiErrorOkDialog(const char *text, std::vector renderBehind) { - UiErrorOkDialog(text, NULL, renderBehind, renderBehind_size); + UiErrorOkDialog(text, NULL, renderBehind); } } // namespace dvl diff --git a/SourceX/DiabloUI/dialogs.h b/SourceX/DiabloUI/dialogs.h index ddff3420d..1d3821a70 100644 --- a/SourceX/DiabloUI/dialogs.h +++ b/SourceX/DiabloUI/dialogs.h @@ -6,8 +6,8 @@ namespace dvl { -void UiErrorOkDialog(const char *text, UiItem *renderBehind, std::size_t renderBehindSize); -void UiErrorOkDialog(const char *text, const char *caption, UiItem *renderBehind, std::size_t renderBehind_size); -void UiOkDialog(const char *text, const char *caption, bool error, UiItem *renderBehind, std::size_t renderBehind_size); +void UiErrorOkDialog(const char *text, std::vector renderBehind); +void UiErrorOkDialog(const char *text, const char *caption, std::vector renderBehind); +void UiOkDialog(const char *text, const char *caption, bool error, std::vector renderBehind); } // namespace dvl diff --git a/SourceX/DiabloUI/mainmenu.cpp b/SourceX/DiabloUI/mainmenu.cpp index 95c3234a4..4cb342a57 100644 --- a/SourceX/DiabloUI/mainmenu.cpp +++ b/SourceX/DiabloUI/mainmenu.cpp @@ -7,20 +7,10 @@ namespace dvl { int mainmenu_attract_time_out; //seconds DWORD dwAttractTicks; +std::vector vecMainMenuDialog; +std::vector vecMenuItems; + int MainMenuResult; -UiListItem MAINMENU_DIALOG_ITEMS[] = { - { "Single Player", MAINMENU_SINGLE_PLAYER }, - { "Multi Player", MAINMENU_MULTIPLAYER }, - { "Replay Intro", MAINMENU_REPLAY_INTRO }, - { "Show Credits", MAINMENU_SHOW_CREDITS }, - { "Exit Diablo", MAINMENU_EXIT_DIABLO } -}; -UiItem MAINMENU_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiList(MAINMENU_DIALOG_ITEMS, PANEL_LEFT + 64, 192, 510, 43, UIS_HUGE | UIS_GOLD | UIS_CENTER), - UiArtText(NULL, { 17, 444, 605, 21 }, UIS_SMALL) -}; void UiMainMenuSelect(int value) { @@ -44,7 +34,20 @@ void mainmenu_restart_repintro() void mainmenu_Load(char *name, void (*fnSound)(char *file)) { gfnSoundFunction = fnSound; - MAINMENU_DIALOG[size(MAINMENU_DIALOG) - 1].art_text.text = name; + + vecMenuItems.push_back(new UiListItem("Single Player", MAINMENU_SINGLE_PLAYER)); + vecMenuItems.push_back(new UiListItem("Multi Player", MAINMENU_MULTIPLAYER)); + vecMenuItems.push_back(new UiListItem("Replay Intro", MAINMENU_REPLAY_INTRO)); + vecMenuItems.push_back(new UiListItem("Show Credits", MAINMENU_SHOW_CREDITS)); + vecMenuItems.push_back(new UiListItem("Exit Diablo", MAINMENU_EXIT_DIABLO)); + + UiAddBackground(&vecMainMenuDialog); + UiAddLogo(&vecMainMenuDialog); + + vecMainMenuDialog.push_back(new UiList(vecMenuItems, PANEL_LEFT + 64, 192, 510, 43, UIS_HUGE | UIS_GOLD | UIS_CENTER)); + + SDL_Rect rect = { 17, 444, 605, 21 }; + vecMainMenuDialog.push_back(new UiArtText(name, rect, UIS_SMALL)); if (!gbSpawned) { LoadBackgroundArt("ui_art\\mainmenu.pcx"); @@ -52,12 +55,25 @@ void mainmenu_Load(char *name, void (*fnSound)(char *file)) LoadBackgroundArt("ui_art\\swmmenu.pcx"); } - UiInitList(MAINMENU_SINGLE_PLAYER, MAINMENU_EXIT_DIABLO, NULL, UiMainMenuSelect, mainmenu_Esc, MAINMENU_DIALOG, size(MAINMENU_DIALOG), true); + UiInitList(MAINMENU_SINGLE_PLAYER, MAINMENU_EXIT_DIABLO, NULL, UiMainMenuSelect, mainmenu_Esc, vecMainMenuDialog, true); } void mainmenu_Free() { ArtBackground.Unload(); + + for (std::size_t i = 0; i < vecMainMenuDialog.size(); i++) { + UiItemBase *pUIItem = vecMainMenuDialog[i]; + delete pUIItem; + } + vecMainMenuDialog.clear(); + + for (std::size_t i = 0; i < vecMenuItems.size(); i++) { + UiListItem *pUIMenuItem = vecMenuItems[i]; + if (pUIMenuItem) + delete pUIMenuItem; + } + vecMenuItems.clear(); } BOOL UiMainMenuDialog(char *name, int *pdwResult, void (*fnSound)(char *file), int attractTimeOut) diff --git a/SourceX/DiabloUI/progress.cpp b/SourceX/DiabloUI/progress.cpp index 1099ac89f..947107b78 100644 --- a/SourceX/DiabloUI/progress.cpp +++ b/SourceX/DiabloUI/progress.cpp @@ -24,13 +24,12 @@ void DialogActionCancel() endMenu = true; } -// TODO use PROGRESS_DIALOG for rendering the progressbar or delete it -UiItem PROGRESS_DIALOG[] = { - UiImage(&dialogArt, { PANEL_LEFT + 180, 168, 280, 144 }), - UiText(dialogText, { PANEL_LEFT + 180, 177, 280, 43 }, UIS_CENTER), - UiImage(&progressArt, { PANEL_LEFT + 205, 220, 228, 38 }), - MakeSmlButton("Cancel", &DialogActionCancel, 330, 265), -}; +//// TODO use PROGRESS_DIALOG for rendering the progressbar or delete it +//UiItem PROGRESS_DIALOG[] = { +// UiImage(&dialogArt, { PANEL_LEFT + 180, 168, 280, 144 }), +// UiText(dialogText, { PANEL_LEFT + 180, 177, 280, 43 }, UIS_CENTER), +// UiImage(&progressArt, { PANEL_LEFT + 205, 220, 228, 38 }), +//}; void progress_Load(char *msg) { diff --git a/SourceX/DiabloUI/scrollbar.h b/SourceX/DiabloUI/scrollbar.h index 655392116..79ef92f12 100644 --- a/SourceX/DiabloUI/scrollbar.h +++ b/SourceX/DiabloUI/scrollbar.h @@ -6,6 +6,8 @@ namespace dvl { extern Art ArtScrollBarBackground; +extern Art ArtScrollBarThumb; +extern Art ArtScrollBarArrow; const Uint16 SCROLLBAR_BG_WIDTH = 25; extern Art ArtScrollBarArrow; @@ -19,57 +21,57 @@ enum ScrollBarArrowFrame { extern Art ArtScrollBarThumb; const Uint16 SCROLLBAR_ARROW_WIDTH = 25; -inline SDL_Rect UpArrowRect(const UiScrollBar &sb) +inline SDL_Rect UpArrowRect(const UiScrollBar *sb) { - return { - sb.rect.x, - sb.rect.y, - SCROLLBAR_ARROW_WIDTH, - static_cast(sb.arrow->h()), - }; + SDL_Rect Tmp; + Tmp.x = sb->m_rect.x; + Tmp.y = sb->m_rect.y; + Tmp.w = SCROLLBAR_ARROW_WIDTH; + Tmp.h = static_cast(sb->m_arrow->h()); + + return Tmp; } -inline SDL_Rect DownArrowRect(const UiScrollBar &sb) +inline SDL_Rect DownArrowRect(const UiScrollBar *sb) { - return { - sb.rect.x, - static_cast(sb.rect.y + sb.rect.h) - sb.arrow->h(), - SCROLLBAR_ARROW_WIDTH, - static_cast(sb.arrow->h()), - }; + SDL_Rect Tmp; + Tmp.x = sb->m_rect.x; + Tmp.y = static_cast(sb->m_rect.y + sb->m_rect.h - sb->m_arrow->h()); + Tmp.w = SCROLLBAR_ARROW_WIDTH, + Tmp.h = static_cast(sb->m_arrow->h()); + + return Tmp; } -inline Uint16 BarHeight(const UiScrollBar &sb) +inline Uint16 BarHeight(const UiScrollBar *sb) { - return sb.rect.h - 2 * sb.arrow->h(); + return sb->m_rect.h - 2 * sb->m_arrow->h(); } -inline SDL_Rect BarRect(const UiScrollBar &sb) +inline SDL_Rect BarRect(const UiScrollBar *sb) { - return { - sb.rect.x, - static_cast(sb.rect.y + sb.arrow->h()), - SCROLLBAR_BG_WIDTH, - BarHeight(sb), - }; + SDL_Rect Tmp; + Tmp.x = sb->m_rect.x; + Tmp.y = static_cast(sb->m_rect.y + sb->m_arrow->h()); + Tmp.w = SCROLLBAR_ARROW_WIDTH, + Tmp.h = BarHeight(sb); + + return Tmp; } -inline SDL_Rect ThumbRect(const UiScrollBar &sb, std::size_t selected_index, std::size_t num_items) +inline SDL_Rect ThumbRect(const UiScrollBar *sb, std::size_t selected_index, std::size_t num_items) { const int THUMB_OFFSET_X = 3; - const int thumb_max_y = BarHeight(sb) - sb.thumb->h(); + const int thumb_max_y = BarHeight(sb) - sb->m_thumb->h(); const int thumb_y = (selected_index * thumb_max_y / (num_items - 1)); - return { - static_cast(sb.rect.x + THUMB_OFFSET_X), - static_cast(sb.rect.y + sb.arrow->h() + thumb_y), - static_cast(sb.rect.w - THUMB_OFFSET_X), - static_cast(sb.thumb->h()), - }; -} -constexpr UiScrollBar MakeScrollBar(SDL_Rect rect) -{ - return UiScrollBar(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, rect); + SDL_Rect Tmp; + Tmp.x = static_cast(sb->m_rect.x + THUMB_OFFSET_X); + Tmp.y = static_cast(sb->m_rect.y + sb->m_arrow->h() + thumb_y); + Tmp.w = static_cast(sb->m_rect.w - THUMB_OFFSET_X); + Tmp.h = static_cast(sb->m_thumb->h()); + + return Tmp; } void LoadScrollBar(); diff --git a/SourceX/DiabloUI/selconn.cpp b/SourceX/DiabloUI/selconn.cpp index ae92f28da..2e50de8f1 100644 --- a/SourceX/DiabloUI/selconn.cpp +++ b/SourceX/DiabloUI/selconn.cpp @@ -18,44 +18,78 @@ _SNETVERSIONDATA *selconn_FileInfo; int provider; -UiArtText SELCONNECT_DIALOG_DESCRIPTION(selconn_Description, { PANEL_LEFT + 35, 275, 205, 66 }); +std::vector vecConnItems; +std::vector vecSelConnDlg; -// Should be in the same order than conn_type (See enums.h) -UiListItem SELCONN_DIALOG_ITEMS[] = { +#define DESCRIPTION_WIDTH 205 + +void selconn_Load() +{ + LoadBackgroundArt("ui_art\\selconn.pcx"); + + // vecConnItems Should be in the same order as conn_type (See enums.h) #ifndef NONET - { "Client-Server (TCP)", SELCONN_TCP }, + vecConnItems.push_back(new UiListItem("Client-Server (TCP)", SELCONN_TCP)); #ifdef BUGGY - { "Peer-to-Peer (UDP)", SELCONN_UDP }, + vecConnItems.push_back(new UiListItem("Peer-to-Peer (UDP)", SELCONN_UDP)); #endif #endif - { "Loopback", SELCONN_LOOPBACK }, -}; - -UiItem SELCONNECT_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiArtText("Multi Player Game", { PANEL_LEFT + 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), - UiArtText(selconn_MaxPlayers, { PANEL_LEFT + 35, 218, 205, 21 }), - UiArtText("Requirements:", { PANEL_LEFT + 35, 256, 205, 21 }), - SELCONNECT_DIALOG_DESCRIPTION, - UiArtText("no gateway needed", { PANEL_LEFT + 30, 356, 220, 31 }, UIS_CENTER | UIS_MED), - UiArtText(selconn_Gateway, { PANEL_LEFT + 35, 393, 205, 21 }, UIS_CENTER), - UiArtText("Select Connection", { PANEL_LEFT + 300, 211, 295, 33 }, UIS_CENTER | UIS_BIG), - UiArtTextButton("Change Gateway", NULL, { PANEL_LEFT + 16, 427, 250, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD | UIS_HIDDEN), - UiList(SELCONN_DIALOG_ITEMS, PANEL_LEFT + 305, 256, 285, 26, UIS_CENTER | UIS_VCENTER | UIS_GOLD), - UiArtTextButton("OK", &UiFocusNavigationSelect, { PANEL_LEFT + 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD), - UiArtTextButton("Cancel", &UiFocusNavigationEsc, { PANEL_LEFT + 454, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD) -}; + vecConnItems.push_back(new UiListItem("Loopback", SELCONN_LOOPBACK)); -void selconn_Load() -{ - LoadBackgroundArt("ui_art\\selconn.pcx"); - UiInitList(0, size(SELCONN_DIALOG_ITEMS) - 1, selconn_Focus, selconn_Select, selconn_Esc, SELCONNECT_DIALOG, size(SELCONNECT_DIALOG)); + UiAddBackground(&vecSelConnDlg); + UiAddLogo(&vecSelConnDlg); + + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelConnDlg.push_back(new UiArtText("Multi Player Game", rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 35, 218, DESCRIPTION_WIDTH, 21 }; + vecSelConnDlg.push_back(new UiArtText(selconn_MaxPlayers, rect2)); + + SDL_Rect rect3 = { PANEL_LEFT + 35, 256, DESCRIPTION_WIDTH, 21 }; + vecSelConnDlg.push_back(new UiArtText("Requirements:", rect3)); + + SDL_Rect rect4 = { PANEL_LEFT + 35, 275, DESCRIPTION_WIDTH, 66 }; + vecSelConnDlg.push_back(new UiArtText(selconn_Description, rect4)); + + SDL_Rect rect5 = { PANEL_LEFT + 30, 356, 220, 31 }; + vecSelConnDlg.push_back(new UiArtText("no gateway needed", rect5, UIS_CENTER | UIS_MED)); + + SDL_Rect rect6 = { PANEL_LEFT + 35, 393, DESCRIPTION_WIDTH, 21 }; + vecSelConnDlg.push_back(new UiArtText(selconn_Gateway, rect6, UIS_CENTER)); + + SDL_Rect rect7 = { PANEL_LEFT + 300, 211, 295, 33 }; + vecSelConnDlg.push_back(new UiArtText("Select Connection", rect7, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect8 = { PANEL_LEFT + 16, 427, 250, 35 }; + vecSelConnDlg.push_back(new UiArtTextButton("Change Gateway", NULL, rect8, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD | UIS_HIDDEN)); + + vecSelConnDlg.push_back(new UiList(vecConnItems, PANEL_LEFT + 305, 256, 285, 26, UIS_CENTER | UIS_VCENTER | UIS_GOLD)); + + SDL_Rect rect9 = { PANEL_LEFT + 299, 427, 140, 35 }; + vecSelConnDlg.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect9, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect10 = { PANEL_LEFT + 454, 427, 140, 35 }; + vecSelConnDlg.push_back(new UiArtTextButton("Cancel", &UiFocusNavigationEsc, rect10, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, vecConnItems.size() - 1, selconn_Focus, selconn_Select, selconn_Esc, vecSelConnDlg); } void selconn_Free() { ArtBackground.Unload(); + + for (std::size_t i = 0; i < vecConnItems.size(); i++) { + UiListItem *pUIItem = vecConnItems[i]; + delete pUIItem; + } + vecConnItems.clear(); + + for (std::size_t i = 0; i < vecSelConnDlg.size(); i++) { + UiItemBase *pUIMenuItem = vecSelConnDlg[i]; + if (pUIMenuItem) + delete pUIMenuItem; + } + vecSelConnDlg.clear(); } void selconn_Esc() @@ -87,7 +121,7 @@ void selconn_Focus(int value) } sprintf(selconn_MaxPlayers, "Players Supported: %d", players); - WordWrapArtStr(selconn_Description, SELCONNECT_DIALOG_DESCRIPTION.rect.w); + WordWrapArtStr(selconn_Description, DESCRIPTION_WIDTH); } void selconn_Select(int value) diff --git a/SourceX/DiabloUI/selgame.cpp b/SourceX/DiabloUI/selgame.cpp index 1f14fa5a8..d15d983cb 100644 --- a/SourceX/DiabloUI/selgame.cpp +++ b/SourceX/DiabloUI/selgame.cpp @@ -23,80 +23,37 @@ int heroLevel; static _SNETPROGRAMDATA *m_client_info; extern int provider; -constexpr UiArtTextButton SELGAME_OK = UiArtTextButton("OK", &UiFocusNavigationSelect, { PANEL_LEFT + 299, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD); -constexpr UiArtTextButton SELGAME_CANCEL = UiArtTextButton("CANCEL", &UiFocusNavigationEsc, { PANEL_LEFT + 449, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD); - -UiArtText SELGAME_DESCRIPTION(selgame_Description, { PANEL_LEFT + 35, 256, 205, 192 }); +#define DESCRIPTION_WIDTH 205 namespace { char title[32]; -UiListItem SELDIFF_DIALOG_ITEMS[] = { - { "Normal", DIFF_NORMAL }, - { "Nightmare", DIFF_NIGHTMARE }, - { "Hell", DIFF_HELL } -}; -UiItem SELDIFF_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiArtText(title, { PANEL_LEFT + 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), - UiArtText(selgame_Label, { PANEL_LEFT + 34, 211, 205, 33 }, UIS_CENTER | UIS_BIG), // DIFF - SELGAME_DESCRIPTION, - UiArtText("Select Difficulty", { PANEL_LEFT + 299, 211, 295, 35 }, UIS_CENTER | UIS_BIG), - UiList(SELDIFF_DIALOG_ITEMS, PANEL_LEFT + 300, 282, 295, 26, UIS_CENTER | UIS_MED | UIS_GOLD), - SELGAME_OK, - SELGAME_CANCEL, -}; - -constexpr UiArtText SELUDPGAME_TITLE = UiArtText(title, { PANEL_LEFT + 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG); -constexpr UiArtText SELUDPGAME_DESCRIPTION_LABEL = UiArtText("Description:", { PANEL_LEFT + 35, 211, 205, 192 }, UIS_MED); - -UiListItem SELUDPGAME_DIALOG_ITEMS[] = { - { "Create Game", 0 }, - { "Join Game", 1 }, -}; -UiItem SELUDPGAME_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - SELUDPGAME_TITLE, - SELUDPGAME_DESCRIPTION_LABEL, - SELGAME_DESCRIPTION, - UiArtText("Select Action", { PANEL_LEFT + 300, 211, 295, 33 }, UIS_CENTER | UIS_BIG), - UiList(SELUDPGAME_DIALOG_ITEMS, PANEL_LEFT + 305, 255, 285, 26, UIS_CENTER | UIS_MED | UIS_GOLD), - SELGAME_OK, - SELGAME_CANCEL, -}; - -UiItem ENTERIP_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - SELUDPGAME_TITLE, - SELUDPGAME_DESCRIPTION_LABEL, - SELGAME_DESCRIPTION, - UiArtText("Enter address", { PANEL_LEFT + 305, 211, 285, 33 }, UIS_CENTER | UIS_BIG), - - UiEdit(selgame_Ip, 128, { PANEL_LEFT + 305, 314, 285, 33 }, UIS_MED | UIS_GOLD), - SELGAME_OK, - SELGAME_CANCEL, -}; - -UiItem ENTERPASSWORD_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - SELUDPGAME_TITLE, - SELUDPGAME_DESCRIPTION_LABEL, - SELGAME_DESCRIPTION, - UiArtText("Enter Password", { PANEL_LEFT + 305, 211, 285, 33 }, UIS_CENTER | UIS_BIG), - UiEdit(selgame_Password, 15, { PANEL_LEFT + 305, 314, 285, 33 }, UIS_MED | UIS_GOLD), - SELGAME_OK, - SELGAME_CANCEL, -}; + +std::vector vecSelGameDlgItems; +std::vector vecSelGameDialog; } // namespace +void selgame_FreeVectors() +{ + for (std::size_t i = 0; i < vecSelGameDlgItems.size(); i++) { + UiListItem *pUIItem = vecSelGameDlgItems[i]; + delete pUIItem; + } + vecSelGameDlgItems.clear(); + + for (std::size_t i = 0; i < vecSelGameDialog.size(); i++) { + UiItemBase *pUIItem = vecSelGameDialog[i]; + delete pUIItem; + } + vecSelGameDialog.clear(); +} + void selgame_Free() { ArtBackground.Unload(); + + selgame_FreeVectors(); } void selgame_GameSelection_Init() @@ -111,8 +68,36 @@ void selgame_GameSelection_Init() } getIniValue("Phone Book", "Entry1", selgame_Ip, 128); - strcpy(title, "Client-Server (TCP)"); - UiInitList(0, 1, selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, SELUDPGAME_DIALOG, size(SELUDPGAME_DIALOG)); + + selgame_FreeVectors(); + + UiAddBackground(&vecSelGameDialog); + UiAddLogo(&vecSelGameDialog); + + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelGameDialog.push_back(new UiArtText("Client-Server (TCP)", rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 35, 211, 205, 192 }; + vecSelGameDialog.push_back(new UiArtText("Description:", rect2, UIS_MED)); + + SDL_Rect rect3 = { PANEL_LEFT + 35, 256, DESCRIPTION_WIDTH, 192 }; + vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3)); + + SDL_Rect rect4 = { PANEL_LEFT + 300, 211, 295, 33 }; + vecSelGameDialog.push_back(new UiArtText("Select Action", rect4, UIS_CENTER | UIS_BIG)); + + vecSelGameDlgItems.push_back(new UiListItem("Create Game", 0)); + vecSelGameDlgItems.push_back(new UiListItem("Join Game", 1)); + + vecSelGameDialog.push_back(new UiList(vecSelGameDlgItems, PANEL_LEFT + 305, 255, 285, 26, UIS_CENTER | UIS_MED | UIS_GOLD)); + + SDL_Rect rect5 = { PANEL_LEFT + 299, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect5, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect6 = { PANEL_LEFT + 449, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 1, selgame_GameSelection_Focus, selgame_GameSelection_Select, selgame_GameSelection_Esc, vecSelGameDialog); } void selgame_GameSelection_Focus(int value) @@ -125,7 +110,7 @@ void selgame_GameSelection_Focus(int value) strcpy(selgame_Description, "Enter an IP or a hostname and join a game already in progress at that address."); break; } - WordWrapArtStr(selgame_Description, SELGAME_DESCRIPTION.rect.w); + WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH); } /** @@ -148,21 +133,65 @@ void selgame_GameSelection_Select(int value) gfnHeroInfo(UpdateHeroLevel); + selgame_FreeVectors(); + + UiAddBackground(&vecSelGameDialog); + UiAddLogo(&vecSelGameDialog); + + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelGameDialog.push_back(new UiArtText(title, rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 34, 211, 205, 33 }; + vecSelGameDialog.push_back(new UiArtText(selgame_Label, rect2, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect3 = { PANEL_LEFT + 35, 256, DESCRIPTION_WIDTH, 192 }; + vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3)); + switch (value) { - case 0: + case 0: { strcpy(title, "Create Game"); - UiInitList(0, NUM_DIFFICULTIES - 1, selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, SELDIFF_DIALOG, size(SELDIFF_DIALOG)); + + SDL_Rect rect4 = { PANEL_LEFT + 299, 211, 295, 35 }; + vecSelGameDialog.push_back(new UiArtText("Select Difficulty", rect4, UIS_CENTER | UIS_BIG)); + + vecSelGameDlgItems.push_back(new UiListItem("Normal", DIFF_NORMAL)); + vecSelGameDlgItems.push_back(new UiListItem("Nightmare", DIFF_NIGHTMARE)); + vecSelGameDlgItems.push_back(new UiListItem("Hell", DIFF_HELL)); + + vecSelGameDialog.push_back(new UiList(vecSelGameDlgItems, PANEL_LEFT + 300, 282, 295, 26, UIS_CENTER | UIS_MED | UIS_GOLD)); + + SDL_Rect rect5 = { PANEL_LEFT + 299, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect5, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect6 = { PANEL_LEFT + 449, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, NUM_DIFFICULTIES - 1, selgame_Diff_Focus, selgame_Diff_Select, selgame_Diff_Esc, vecSelGameDialog); break; + } case 1: strcpy(title, "Join TCP Games"); - UiInitList(0, 0, NULL, selgame_Password_Init, selgame_GameSelection_Init, ENTERIP_DIALOG, size(ENTERIP_DIALOG)); + + SDL_Rect rect4 = { PANEL_LEFT + 305, 211, 285, 33 }; + vecSelGameDialog.push_back(new UiArtText("Enter address", rect4, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect5 = { PANEL_LEFT + 305, 314, 285, 33 }; + vecSelGameDialog.push_back(new UiEdit(selgame_Ip, 128, rect5, UIS_MED | UIS_GOLD)); + + SDL_Rect rect6 = { PANEL_LEFT + 299, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect7 = { PANEL_LEFT + 449, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect7, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 0, NULL, selgame_Password_Init, selgame_GameSelection_Init, vecSelGameDialog); break; } } void selgame_GameSelection_Esc() { - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); selgame_enteringGame = false; selgame_endMenu = true; } @@ -183,7 +212,7 @@ void selgame_Diff_Focus(int value) strcpy(selgame_Description, "Hell Difficulty\nThe most powerful of the underworld's creatures lurk at the gateway into Hell. Only the most experienced characters should venture in this realm."); break; } - WordWrapArtStr(selgame_Description, SELGAME_DESCRIPTION.rect.w); + WordWrapArtStr(selgame_Description, DESCRIPTION_WIDTH); } bool IsDifficultyAllowed(int value) @@ -234,7 +263,34 @@ void selgame_Diff_Esc() void selgame_Password_Init(int value) { memset(&selgame_Password, 0, sizeof(selgame_Password)); - UiInitList(0, 0, NULL, selgame_Password_Select, selgame_Password_Esc, ENTERPASSWORD_DIALOG, size(ENTERPASSWORD_DIALOG)); + + selgame_FreeVectors(); + + UiAddBackground(&vecSelGameDialog); + UiAddLogo(&vecSelGameDialog); + + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelGameDialog.push_back(new UiArtText("Client-Server (TCP)", rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 35, 211, 205, 192 }; + vecSelGameDialog.push_back(new UiArtText("Description:", rect2, UIS_MED)); + + SDL_Rect rect3 = { PANEL_LEFT + 35, 256, DESCRIPTION_WIDTH, 192 }; + vecSelGameDialog.push_back(new UiArtText(selgame_Description, rect3)); + + SDL_Rect rect4 = { PANEL_LEFT + 305, 211, 285, 33 }; + vecSelGameDialog.push_back(new UiArtText("Enter Password", rect4, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect5 = { PANEL_LEFT + 305, 314, 285, 33 }; + vecSelGameDialog.push_back(new UiEdit(selgame_Password, 15, rect5, UIS_MED | UIS_GOLD)); + + SDL_Rect rect6 = { PANEL_LEFT + 299, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect6, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect7 = { PANEL_LEFT + 449, 427, 140, 35 }; + vecSelGameDialog.push_back(new UiArtTextButton("CANCEL", &UiFocusNavigationEsc, rect7, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 0, NULL, selgame_Password_Select, selgame_Password_Esc, vecSelGameDialog); } void selgame_Password_Select(int value) @@ -247,7 +303,7 @@ void selgame_Password_Select(int value) return; } - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); selgame_endMenu = true; } else { selgame_Free(); @@ -262,7 +318,7 @@ void selgame_Password_Select(int value) info->bDiff = gbDifficulty; if (SNetCreateGame(NULL, selgame_Password, NULL, 0, (char *)info, sizeof(_gamedata), MAX_PLRS, NULL, NULL, gdwPlayerId)) { - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); selgame_endMenu = true; } else { selgame_Free(); diff --git a/SourceX/DiabloUI/selhero.cpp b/SourceX/DiabloUI/selhero.cpp index 366bf3317..fc7877ff8 100644 --- a/SourceX/DiabloUI/selhero.cpp +++ b/SourceX/DiabloUI/selhero.cpp @@ -14,10 +14,11 @@ namespace dvl { +const char *selhero_GenerateName(uint8_t hero_class); + std::size_t selhero_SaveCount = 0; _uiheroinfo selhero_heros[MAX_CHARACTERS]; _uiheroinfo selhero_heroInfo; -std::size_t listOffset = 0; const size_t kMaxViewportItems = 6; char textStats[5][4]; char title[32]; @@ -29,7 +30,7 @@ bool selhero_isMultiPlayer; bool selhero_navigateYesNo; bool selhero_deleteEnabled; -BOOL (*gfnHeroInfo) +BOOL(*gfnHeroInfo) (BOOL (*fninfofunc)(_uiheroinfo *)); BOOL(*gfnHeroCreate) (_uiheroinfo *); @@ -38,83 +39,58 @@ BOOL(*gfnHeroStats) namespace { -UiItem SELHERO_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiArtText(title, { PANEL_LEFT + 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), - UiImage(&ArtHero, UI_NUM_CLASSES, { PANEL_LEFT + 30, 211, 180, 76 }), - UiArtText("Level:", { PANEL_LEFT + 39, 323, 110, 21 }, UIS_RIGHT), - UiArtText(textStats[0], { PANEL_LEFT + 159, 323, 40, 21 }, UIS_CENTER), - UiArtText("Strength:", { PANEL_LEFT + 39, 358, 110, 21 }, UIS_RIGHT), - UiArtText(textStats[1], { PANEL_LEFT + 159, 358, 40, 21 }, UIS_CENTER), - UiArtText("Magic:", { PANEL_LEFT + 39, 380, 110, 21 }, UIS_RIGHT), - UiArtText(textStats[2], { PANEL_LEFT + 159, 380, 40, 21 }, UIS_CENTER), - UiArtText("Dexterity:", { PANEL_LEFT + 39, 401, 110, 21 }, UIS_RIGHT), - UiArtText(textStats[3], { PANEL_LEFT + 159, 401, 40, 21 }, UIS_CENTER), - UiArtText("Vitality:", { PANEL_LEFT + 39, 422, 110, 21 }, UIS_RIGHT), - UiArtText(textStats[4], { PANEL_LEFT + 159, 422, 40, 21 }, UIS_CENTER), -}; -UiImage *SELHERO_DIALOG_HERO_IMG = &SELHERO_DIALOG[3].image; - -UiListItem SELLIST_DIALOG_ITEMS[kMaxViewportItems]; -UiItem SELLIST_DIALOG[] = { - UiArtText("Select Hero", { PANEL_LEFT + 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG), - UiList(SELLIST_DIALOG_ITEMS, PANEL_LEFT + 265, 256, 320, 26, UIS_CENTER | UIS_MED | UIS_GOLD), - MakeScrollBar({ PANEL_LEFT + 585, 244, 25, 178 }), - UiArtTextButton("OK", &UiFocusNavigationSelect, { PANEL_LEFT + 239, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD), - UiArtTextButton("Delete", &selhero_UiFocusNavigationYesNo, { PANEL_LEFT + 364, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_DISABLED), - UiArtTextButton("Cancel", &UiFocusNavigationEsc, { PANEL_LEFT + 489, 429, 120, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD) -}; -UiList *SELLIST_DIALOG_LIST = &SELLIST_DIALOG[1].list; -UiScrollBar *SELLIST_SCROLLBAR = &SELLIST_DIALOG[2].scrollbar; -UiArtTextButton *SELLIST_DIALOG_DELETE_BUTTON = &SELLIST_DIALOG[4].art_text_button; - -UiListItem SELCLAS_DIALOG_ITEMS[] = { - { "Warrior", UI_WARRIOR }, - { "Rogue", UI_ROGUE }, - { "Sorcerer", UI_SORCERER } -}; -UiItem SELCLASS_DIALOG[] = { - UiArtText("Choose Class", { PANEL_LEFT + 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG), - UiList(SELCLAS_DIALOG_ITEMS, PANEL_LEFT + 264, 285, 320, 33, UIS_CENTER | UIS_MED | UIS_GOLD), - UiArtTextButton("OK", &UiFocusNavigationSelect, { PANEL_LEFT + 279, 429, 140, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD), - UiArtTextButton("Cancel", &UiFocusNavigationEsc, { PANEL_LEFT + 429, 429, 140, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD) -}; - -UiItem ENTERNAME_DIALOG[] = { - UiArtText("Enter Name", { PANEL_LEFT + 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG), - UiEdit(selhero_heroInfo.name, 15, { PANEL_LEFT + 265, 317, 320, 33 }, UIS_MED | UIS_GOLD), - UiArtTextButton("OK", &UiFocusNavigationSelect, { PANEL_LEFT + 279, 429, 140, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD), - UiArtTextButton("Cancel", &UiFocusNavigationEsc, { PANEL_LEFT + 429, 429, 140, 35 }, UIS_CENTER | UIS_BIG | UIS_GOLD) -}; - -UiListItem SELLOAD_DIALOG_ITEMS[] = { - { "Load Game", 0 }, - { "New Game", 1 } -}; -UiItem SELLOAD_DIALOG[] = { - UiArtText("Save File Exists", { PANEL_LEFT + 264, 211, 320, 33 }, UIS_CENTER | UIS_BIG), - UiList(SELLOAD_DIALOG_ITEMS, PANEL_LEFT + 265, 285, 320, 33, UIS_CENTER | UIS_MED | UIS_GOLD), - UiArtTextButton("OK", &UiFocusNavigationSelect, { PANEL_LEFT + 279, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD), - UiArtTextButton("Cancel", &UiFocusNavigationEsc, { PANEL_LEFT + 429, 427, 140, 35 }, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD) -}; +std::vector vecSelHeroDialog; +std::vector vecSelHeroDlgItems; +std::vector vecSelDlgItems; +UiImage *SELHERO_DIALOG_HERO_IMG; } // namespace +bool bUIElementsLoaded = false; + void selhero_UiFocusNavigationYesNo() { if (selhero_deleteEnabled) UiFocusNavigationYesNo(); } +void selhero_FreeListItems() +{ + for (std::size_t i = 0; i < vecSelHeroDlgItems.size(); i++) { + UiListItem *pUIItem = vecSelHeroDlgItems[i]; + delete pUIItem; + } + vecSelHeroDlgItems.clear(); +} + +void selhero_FreeDlgItems() +{ + for (std::size_t i = 0; i < vecSelDlgItems.size(); i++) { + UiItemBase *pUIItem = vecSelDlgItems[i]; + delete pUIItem; + } + vecSelDlgItems.clear(); +} + void selhero_Free() { ArtBackground.Unload(); + + for (std::size_t i = 0; i < vecSelHeroDialog.size(); i++) { + UiItemBase *pUIItem = vecSelHeroDialog[i]; + delete pUIItem; + } + vecSelHeroDialog.clear(); + + selhero_FreeDlgItems(); + selhero_FreeListItems(); + + bUIElementsLoaded = false; } void selhero_SetStats() { - SELHERO_DIALOG_HERO_IMG->frame = selhero_heroInfo.heroclass; + SELHERO_DIALOG_HERO_IMG->m_frame = selhero_heroInfo.heroclass; sprintf(textStats[0], "%d", selhero_heroInfo.level); sprintf(textStats[1], "%d", selhero_heroInfo.strength); sprintf(textStats[2], "%d", selhero_heroInfo.magic); @@ -124,17 +100,20 @@ void selhero_SetStats() namespace { +std::size_t listOffset = 0; +UiArtTextButton *SELLIST_DIALOG_DELETE_BUTTON; + void selhero_UpdateViewportItems() { const std::size_t num_viewport_heroes = std::min(selhero_SaveCount - listOffset, kMaxViewportItems); - SELLIST_DIALOG_LIST->length = num_viewport_heroes; for (std::size_t i = 0; i < num_viewport_heroes; i++) { const std::size_t index = i + listOffset; - SELLIST_DIALOG_ITEMS[i] = { selhero_heros[index].name, static_cast(index) }; + vecSelHeroDlgItems[i]->m_text = selhero_heros[index].name; + vecSelHeroDlgItems[i]->m_value = static_cast(index); } if (num_viewport_heroes < kMaxViewportItems) { - SELLIST_DIALOG_ITEMS[num_viewport_heroes] = { "New Hero", static_cast(selhero_SaveCount) }; - ++SELLIST_DIALOG_LIST->length; + vecSelHeroDlgItems[num_viewport_heroes]->m_text = "New Hero"; + vecSelHeroDlgItems[num_viewport_heroes]->m_value = static_cast(selhero_SaveCount); } } @@ -156,9 +135,36 @@ void selhero_ScrollIntoView(std::size_t index) void selhero_List_Init() { listOffset = 0; + selhero_FreeDlgItems(); + + SDL_Rect rect1 = { PANEL_LEFT + 264, 211, 320, 33 }; + vecSelDlgItems.push_back(new UiArtText("Select Hero", rect1, UIS_CENTER | UIS_BIG)); + + selhero_FreeListItems(); + const size_t num_viewport_heroes = std::min(selhero_SaveCount + 1, kMaxViewportItems); + for (std::size_t i = 0; i < num_viewport_heroes; i++) { + vecSelHeroDlgItems.push_back(new UiListItem("", -1)); + } selhero_UpdateViewportItems(); - UiInitList(0, selhero_SaveCount, selhero_List_Focus, selhero_List_Select, selhero_List_Esc, SELLIST_DIALOG, size(SELLIST_DIALOG), false, selhero_List_DeleteYesNo); - UiInitScrollBar(SELLIST_SCROLLBAR, kMaxViewportItems, &listOffset); + + vecSelDlgItems.push_back(new UiList(vecSelHeroDlgItems, PANEL_LEFT + 265, 256, 320, 26, UIS_CENTER | UIS_MED | UIS_GOLD)); + + SDL_Rect rect2 = { PANEL_LEFT + 585, 244, 25, 178 }; + UiScrollBar *scrollBar = new UiScrollBar(&ArtScrollBarBackground, &ArtScrollBarThumb, &ArtScrollBarArrow, rect2); + vecSelDlgItems.push_back(scrollBar); + + SDL_Rect rect3 = { PANEL_LEFT + 239, 429, 120, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect3, UIS_CENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect4 = { PANEL_LEFT + 364, 429, 120, 35 }; + SELLIST_DIALOG_DELETE_BUTTON = new UiArtTextButton("Delete", &selhero_UiFocusNavigationYesNo, rect4, UIS_CENTER | UIS_BIG | UIS_DISABLED); + vecSelDlgItems.push_back(SELLIST_DIALOG_DELETE_BUTTON); + + SDL_Rect rect5 = { PANEL_LEFT + 489, 429, 120, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("Cancel", &UiFocusNavigationEsc, rect5, UIS_CENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, selhero_SaveCount, selhero_List_Focus, selhero_List_Select, selhero_List_Esc, vecSelDlgItems, false, selhero_List_DeleteYesNo); + UiInitScrollBar(scrollBar, kMaxViewportItems, &listOffset); if (selhero_isMultiPlayer) { strcpy(title, "Multi Player Characters"); } else { @@ -174,18 +180,18 @@ void selhero_List_Focus(int value) if (selhero_SaveCount && index < selhero_SaveCount) { memcpy(&selhero_heroInfo, &selhero_heros[index], sizeof(selhero_heroInfo)); selhero_SetStats(); - SELLIST_DIALOG_DELETE_BUTTON->flags = baseFlags | UIS_GOLD; + SELLIST_DIALOG_DELETE_BUTTON->m_iFlags = baseFlags | UIS_GOLD; selhero_deleteEnabled = true; return; } - SELHERO_DIALOG_HERO_IMG->frame = UI_NUM_CLASSES; + SELHERO_DIALOG_HERO_IMG->m_frame = UI_NUM_CLASSES; strcpy(textStats[0], "--"); strcpy(textStats[1], "--"); strcpy(textStats[2], "--"); strcpy(textStats[3], "--"); strcpy(textStats[4], "--"); - SELLIST_DIALOG_DELETE_BUTTON->flags = baseFlags | UIS_DISABLED; + SELLIST_DIALOG_DELETE_BUTTON->m_iFlags = baseFlags | UIS_DISABLED; selhero_deleteEnabled = false; } @@ -199,26 +205,62 @@ bool selhero_List_DeleteYesNo() void selhero_List_Select(int value) { if (static_cast(value) == selhero_SaveCount) { - UiInitList(0, 2, selhero_ClassSelector_Focus, selhero_ClassSelector_Select, selhero_ClassSelector_Esc, SELCLASS_DIALOG, size(SELCLASS_DIALOG)); + selhero_FreeDlgItems(); + + SDL_Rect rect1 = { PANEL_LEFT + 264, 211, 320, 33 }; + vecSelDlgItems.push_back(new UiArtText("Choose Class", rect1, UIS_CENTER | UIS_BIG)); + + selhero_FreeListItems(); + vecSelHeroDlgItems.push_back(new UiListItem("Warrior", UI_WARRIOR)); + vecSelHeroDlgItems.push_back(new UiListItem("Rogue", UI_ROGUE)); + vecSelHeroDlgItems.push_back(new UiListItem("Sorcerer", UI_SORCERER)); + vecSelDlgItems.push_back(new UiList(vecSelHeroDlgItems, PANEL_LEFT + 264, 285, 320, 33, UIS_CENTER | UIS_MED | UIS_GOLD)); + + SDL_Rect rect2 = { PANEL_LEFT + 279, 429, 140, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect2, UIS_CENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect3 = { PANEL_LEFT + 429, 429, 140, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("Cancel", &UiFocusNavigationEsc, rect3, UIS_CENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 2, selhero_ClassSelector_Focus, selhero_ClassSelector_Select, selhero_ClassSelector_Esc, vecSelDlgItems); memset(&selhero_heroInfo.name, 0, sizeof(selhero_heroInfo.name)); strcpy(title, "New Single Player Hero"); if (selhero_isMultiPlayer) { strcpy(title, "New Multi Player Hero"); } return; - } else if (selhero_heroInfo.hassaved) { - UiInitList(0, 1, selhero_Load_Focus, selhero_Load_Select, selhero_List_Init, SELLOAD_DIALOG, size(SELLOAD_DIALOG), true); + } + + if (selhero_heroInfo.hassaved) { + selhero_FreeDlgItems(); + + SDL_Rect rect1 = { PANEL_LEFT + 264, 211, 320, 33 }; + vecSelDlgItems.push_back(new UiArtText("Save File Exists", rect1, UIS_CENTER | UIS_BIG)); + + selhero_FreeListItems(); + vecSelHeroDlgItems.push_back(new UiListItem("Load Game", 0)); + vecSelHeroDlgItems.push_back(new UiListItem("New Game", 1)); + vecSelDlgItems.push_back(new UiList(vecSelHeroDlgItems, PANEL_LEFT + 265, 285, 320, 33, UIS_CENTER | UIS_MED | UIS_GOLD)); + + SDL_Rect rect2 = { PANEL_LEFT + 279, 427, 140, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect2, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect3 = { PANEL_LEFT + 429, 427, 140, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("Cancel", &UiFocusNavigationEsc, rect3, UIS_CENTER | UIS_VCENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 1, selhero_Load_Focus, selhero_Load_Select, selhero_List_Init, vecSelDlgItems, true); strcpy(title, "Single Player Characters"); return; } - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); selhero_endMenu = true; } void selhero_List_Esc() { - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); + selhero_endMenu = true; selhero_result = SELHERO_PREVIOUS; } @@ -241,7 +283,7 @@ void selhero_ClassSelector_Focus(int value) void selhero_ClassSelector_Select(int value) { if (gbSpawned && (value == 1 || value == 2)) { - selhero_Free(); + ArtBackground.Unload(); UiSelOkDialog(NULL, "The Rogue and Sorcerer are only available in the full retail version of Diablo. Visit https://www.gog.com/game/diablo to purchase.", false); LoadBackgroundArt("ui_art\\selhero.pcx"); selhero_List_Select(selhero_SaveCount); @@ -256,11 +298,27 @@ void selhero_ClassSelector_Select(int value) #ifdef PREFILL_PLAYER_NAME strcpy(selhero_heroInfo.name, selhero_GenerateName(selhero_heroInfo.heroclass)); #endif - UiInitList(0, 0, NULL, selhero_Name_Select, selhero_Name_Esc, ENTERNAME_DIALOG, size(ENTERNAME_DIALOG)); + selhero_FreeDlgItems(); + SDL_Rect rect1 = { PANEL_LEFT + 264, 211, 320, 33 }; + vecSelDlgItems.push_back(new UiArtText("Enter Name", rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 265, 317, 320, 33 }; + vecSelDlgItems.push_back(new UiEdit(selhero_heroInfo.name, 15, rect2, UIS_MED | UIS_GOLD)); + + SDL_Rect rect3 = { PANEL_LEFT + 279, 429, 140, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("OK", &UiFocusNavigationSelect, rect3, UIS_CENTER | UIS_BIG | UIS_GOLD)); + + SDL_Rect rect4 = { PANEL_LEFT + 429, 429, 140, 35 }; + vecSelDlgItems.push_back(new UiArtTextButton("Cancel", &UiFocusNavigationEsc, rect4, UIS_CENTER | UIS_BIG | UIS_GOLD)); + + UiInitList(0, 0, NULL, selhero_Name_Select, selhero_Name_Esc, vecSelDlgItems); } void selhero_ClassSelector_Esc() { + selhero_FreeDlgItems(); + selhero_FreeListItems(); + if (selhero_SaveCount) { selhero_List_Init(); return; @@ -273,14 +331,14 @@ void selhero_Name_Select(int value) { if (!UiValidPlayerName(selhero_heroInfo.name)) { - selhero_Free(); + ArtBackground.Unload(); UiSelOkDialog(title, "Invalid name. A name cannot contain spaces, reserved characters, or reserved words.\n", false); LoadBackgroundArt("ui_art\\selhero.pcx"); } else { bool overwrite = true; for (std::size_t i = 0; i < selhero_SaveCount; i++) { if (strcasecmp(selhero_heros[i].name, selhero_heroInfo.name) == 0) { - selhero_Free(); + ArtBackground.Unload(); char dialogText[256]; sprintf(dialogText, "Character already exists. Do you want to overwrite \"%s\"?", selhero_heroInfo.name); overwrite = UiSelHeroYesNoDialog(title, dialogText); @@ -291,11 +349,11 @@ void selhero_Name_Select(int value) if (overwrite) { if (gfnHeroCreate(&selhero_heroInfo)) { - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); selhero_endMenu = true; return; } else { - UiErrorOkDialog("Unable to create character.", SELHERO_DIALOG, size(SELHERO_DIALOG)); + UiErrorOkDialog("Unable to create character.", vecSelDlgItems); } } } @@ -318,7 +376,7 @@ void selhero_Load_Focus(int value) void selhero_Load_Select(int value) { - UiInitList(0, 0, NULL, NULL, NULL, NULL, 0); + UiInitList_clear(); selhero_endMenu = true; if (value == 0) { selhero_result = SELHERO_CONTINUE; @@ -344,10 +402,50 @@ BOOL UiSelHeroDialog( int *dlgresult, char *name) { + bUIElementsLoaded = true; + do { LoadBackgroundArt("ui_art\\selhero.pcx"); + UiAddBackground(&vecSelHeroDialog); + UiAddLogo(&vecSelHeroDialog); LoadScrollBar(); + selhero_FreeDlgItems(); + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelHeroDialog.push_back(new UiArtText(title, rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 30, 211, 180, 76 }; + SELHERO_DIALOG_HERO_IMG = new UiImage(&ArtHero, UI_NUM_CLASSES, rect2); + vecSelHeroDialog.push_back(SELHERO_DIALOG_HERO_IMG); + + SDL_Rect rect3 = { PANEL_LEFT + 39, 323, 110, 21 }; + vecSelHeroDialog.push_back(new UiArtText("Level:", rect3, UIS_RIGHT)); + + SDL_Rect rect4 = { PANEL_LEFT + 39, 323, 110, 21 }; + vecSelHeroDialog.push_back(new UiArtText("Level:", rect4, UIS_RIGHT)); + SDL_Rect rect5 = { PANEL_LEFT + 159, 323, 40, 21 }; + vecSelHeroDialog.push_back(new UiArtText(textStats[0], rect5, UIS_CENTER)); + + SDL_Rect rect6 = { PANEL_LEFT + 39, 358, 110, 21 }; + vecSelHeroDialog.push_back(new UiArtText("Strength:", rect6, UIS_RIGHT)); + SDL_Rect rect7 = { PANEL_LEFT + 159, 358, 40, 21 }; + vecSelHeroDialog.push_back(new UiArtText(textStats[1], rect7, UIS_CENTER)); + + SDL_Rect rect8 = { PANEL_LEFT + 39, 380, 110, 21 }; + vecSelHeroDialog.push_back(new UiArtText("Magic:", rect8, UIS_RIGHT)); + SDL_Rect rect9 = { PANEL_LEFT + 159, 380, 40, 21 }; + vecSelHeroDialog.push_back(new UiArtText(textStats[2], rect9, UIS_CENTER)); + + SDL_Rect rect10 = { PANEL_LEFT + 39, 401, 110, 21 }; + vecSelHeroDialog.push_back(new UiArtText("Dexterity:", rect10, UIS_RIGHT)); + SDL_Rect rect11 = { PANEL_LEFT + 159, 401, 40, 21 }; + vecSelHeroDialog.push_back(new UiArtText(textStats[3], rect11, UIS_CENTER)); + + SDL_Rect rect12 = { PANEL_LEFT + 39, 422, 110, 21 }; + vecSelHeroDialog.push_back(new UiArtText("Vitality:", rect12, UIS_RIGHT)); + SDL_Rect rect13 = { PANEL_LEFT + 159, 422, 40, 21 }; + vecSelHeroDialog.push_back(new UiArtText(textStats[4], rect13, UIS_CENTER)); + gfnHeroInfo = fninfo; gfnHeroCreate = fncreate; gfnHeroStats = fnstats; @@ -368,7 +466,7 @@ BOOL UiSelHeroDialog( selhero_endMenu = false; while (!selhero_endMenu && !selhero_navigateYesNo) { UiClearScreen(); - UiRenderItems(SELHERO_DIALOG, size(SELHERO_DIALOG)); + UiRenderItems(vecSelHeroDialog); UiPollAndRender(); } selhero_Free(); @@ -421,7 +519,7 @@ BOOL UiSelHeroMultDialog( return UiSelHeroDialog(fninfo, fncreate, fnstats, fnremove, dlgresult, name); } -const char *selhero_GenerateName(std::uint8_t hero_class) +const char *selhero_GenerateName(uint8_t hero_class) { static const char *const kNames[3][10] = { { @@ -461,10 +559,10 @@ const char *selhero_GenerateName(std::uint8_t hero_class) "Horazon", } }; - const int seed = std::chrono::system_clock::now().time_since_epoch().count(); - std::default_random_engine generator(seed); - std::uniform_int_distribution dist(0, sizeof(kNames[0]) / sizeof(kNames[0][0]) - 1); - return kNames[hero_class][dist(generator)]; + + int iRand = rand() % 9; + + return kNames[hero_class][iRand]; } } // namespace dvl diff --git a/SourceX/DiabloUI/selhero.h b/SourceX/DiabloUI/selhero.h index 616fa9a5b..33d77bcf1 100644 --- a/SourceX/DiabloUI/selhero.h +++ b/SourceX/DiabloUI/selhero.h @@ -17,6 +17,5 @@ void selhero_Name_Select(int value); void selhero_Name_Esc(); void selhero_Load_Focus(int value); void selhero_Load_Select(int value); -const char *selhero_GenerateName(std::uint8_t hero_class); } // namespace dvl diff --git a/SourceX/DiabloUI/selok.cpp b/SourceX/DiabloUI/selok.cpp index 6e2745c90..e019e9616 100644 --- a/SourceX/DiabloUI/selok.cpp +++ b/SourceX/DiabloUI/selok.cpp @@ -12,11 +12,28 @@ char dialogText[256]; } // namespace int selok_endMenu; -char selok_title[32]; + +std::vector vecSelOkDialogItems; +std::vector vecSelOkDialog; + +#define MESSAGE_WIDTH 280 void selok_Free() { ArtBackground.Unload(); + + for (std::size_t i = 0; i < vecSelOkDialogItems.size(); i++) { + UiListItem *pUIListItem = vecSelOkDialogItems[i]; + if (pUIListItem) + delete pUIListItem; + } + vecSelOkDialogItems.clear(); + + for (std::size_t i = 0; i < vecSelOkDialog.size(); i++) { + UiItemBase *pUIItem = vecSelOkDialog[i]; + delete pUIItem; + } + vecSelOkDialog.clear(); } void selok_Select(int value) @@ -29,25 +46,6 @@ void selok_Esc() selok_endMenu = true; } -UiListItem SELOK_DIALOG_ITEMS[] = { - { "OK", 0 } -}; - -UiItem SELOK_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiArtText(selok_title, { PANEL_LEFT + 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), - UiArtText(dialogText, { PANEL_LEFT + 140, 210, 560, 168 }, UIS_MED), - UiList(SELOK_DIALOG_ITEMS, PANEL_LEFT + 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD) -}; - -UiItem SPAWNERR_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiArtText(dialogText, { PANEL_LEFT + 140, 197, 560, 168 }, UIS_MED), - UiList(SELOK_DIALOG_ITEMS, PANEL_LEFT + 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD) -}; - void UiSelOkDialog(const char *title, const char *body, bool background) { if (!background) { @@ -60,23 +58,35 @@ void UiSelOkDialog(const char *title, const char *body, bool background) } } - UiItem *items = SPAWNERR_DIALOG; - int itemCnt = size(SPAWNERR_DIALOG); + UiAddBackground(&vecSelOkDialog); + UiAddLogo(&vecSelOkDialog); + if (title != NULL) { - strcpy(selok_title, title); - items = SELOK_DIALOG; - itemCnt = size(SELOK_DIALOG); + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelOkDialog.push_back(new UiArtText(title, rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 140, 210, 560, 168 }; + vecSelOkDialog.push_back(new UiArtText(dialogText, rect2, UIS_MED)); + } else { + SDL_Rect rect1 = { PANEL_LEFT + 140, 197, 560, 168 }; + vecSelOkDialog.push_back(new UiArtText(dialogText, rect1, UIS_MED)); } + SDL_Rect rect3 = { PANEL_LEFT + 140, 210, 560, 168 }; + vecSelOkDialog.push_back(new UiArtText(dialogText, rect3, UIS_MED)); + + vecSelOkDialogItems.push_back(new UiListItem("OK", 0)); + vecSelOkDialog.push_back(new UiList(vecSelOkDialogItems, PANEL_LEFT + 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD)); + strcpy(dialogText, body); - WordWrapArtStr(dialogText, 280); + WordWrapArtStr(dialogText, MESSAGE_WIDTH); - UiInitList(0, 0, NULL, selok_Select, selok_Esc, items, itemCnt, false, NULL); + UiInitList(0, 0, NULL, selok_Select, selok_Esc, vecSelOkDialog, false, NULL); selok_endMenu = false; while (!selok_endMenu) { UiClearScreen(); - UiRenderItems(items, itemCnt); + UiRenderItems(vecSelOkDialog); UiPollAndRender(); } diff --git a/SourceX/DiabloUI/selyesno.cpp b/SourceX/DiabloUI/selyesno.cpp index cc938fd74..77a56e630 100644 --- a/SourceX/DiabloUI/selyesno.cpp +++ b/SourceX/DiabloUI/selyesno.cpp @@ -9,25 +9,28 @@ namespace dvl { bool selyesno_endMenu; bool selyesno_value; char selyesno_confirmationMessage[256]; -char selyesno_title[32]; - -UiListItem SELYESNO_DIALOG_ITEMS[] = { - { "Yes", 0 }, - { "No", 1 } -}; - -UiItem SELYESNO_DIALOG[] = { - MAINMENU_BACKGROUND, - MAINMENU_LOGO, - UiArtText(selyesno_title, { PANEL_LEFT + 24, 161, 590, 35 }, UIS_CENTER | UIS_BIG), - UiArtText(selyesno_confirmationMessage, { PANEL_LEFT + 120, 236, 280, 168 }, UIS_MED), - UiList(SELYESNO_DIALOG_ITEMS, PANEL_LEFT + 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD) -}; -UiArtText *SELYESNO_DIALOG_CONFIRMATION_MESSAGE = &SELYESNO_DIALOG[3].art_text; + +std::vector vecSelYesNoDialogItems; +std::vector vecSelYesNoDialog; + +#define MESSAGE_WIDTH 280 void selyesno_Free() { ArtBackground.Unload(); + + for (std::size_t i = 0; i < vecSelYesNoDialogItems.size(); i++) { + UiListItem *pUIListItem = vecSelYesNoDialogItems[i]; + if (pUIListItem) + delete pUIListItem; + } + vecSelYesNoDialogItems.clear(); + + for (std::size_t i = 0; i < vecSelYesNoDialog.size(); i++) { + UiItemBase *pUIItem = vecSelYesNoDialog[i]; + delete pUIItem; + } + vecSelYesNoDialog.clear(); } void selyesno_Select(int value) @@ -45,18 +48,29 @@ void selyesno_Esc() bool UiSelHeroYesNoDialog(const char *title, const char *body) { LoadBackgroundArt("ui_art\\black.pcx"); + UiAddBackground(&vecSelYesNoDialog); + UiAddLogo(&vecSelYesNoDialog); + + SDL_Rect rect1 = { PANEL_LEFT + 24, 161, 590, 35 }; + vecSelYesNoDialog.push_back(new UiArtText(title, rect1, UIS_CENTER | UIS_BIG)); + + SDL_Rect rect2 = { PANEL_LEFT + 120, 236, MESSAGE_WIDTH, 168 }; + vecSelYesNoDialog.push_back(new UiArtText(selyesno_confirmationMessage, rect2, UIS_MED)); + + vecSelYesNoDialogItems.push_back(new UiListItem("Yes", 0)); + vecSelYesNoDialogItems.push_back(new UiListItem("No", 1)); + vecSelYesNoDialog.push_back(new UiList(vecSelYesNoDialogItems, PANEL_LEFT + 230, 390, 180, 35, UIS_CENTER | UIS_BIG | UIS_GOLD)); - strcpy(selyesno_title, title); strcpy(selyesno_confirmationMessage, body); - WordWrapArtStr(selyesno_confirmationMessage, SELYESNO_DIALOG_CONFIRMATION_MESSAGE->rect.w); + WordWrapArtStr(selyesno_confirmationMessage, MESSAGE_WIDTH); - UiInitList(0, 1, NULL, selyesno_Select, selyesno_Esc, SELYESNO_DIALOG, size(SELYESNO_DIALOG), true, NULL); + UiInitList(0, 1, NULL, selyesno_Select, selyesno_Esc, vecSelYesNoDialog, true, NULL); selyesno_value = true; selyesno_endMenu = false; while (!selyesno_endMenu) { UiClearScreen(); - UiRenderItems(SELYESNO_DIALOG, size(SELYESNO_DIALOG)); + UiRenderItems(vecSelYesNoDialog); UiPollAndRender(); } @@ -64,4 +78,4 @@ bool UiSelHeroYesNoDialog(const char *title, const char *body) return selyesno_value; } -} +} // namespace dvl diff --git a/SourceX/DiabloUI/text_draw.cpp b/SourceX/DiabloUI/text_draw.cpp index bcb319ce0..c8ac80105 100644 --- a/SourceX/DiabloUI/text_draw.cpp +++ b/SourceX/DiabloUI/text_draw.cpp @@ -42,7 +42,7 @@ void DrawTTF(const char *text, const SDL_Rect &rectIn, int flags, return; if (*render_cache == NULL) { *render_cache = new TtfSurfaceCache(); - const TextAlignment x_align = XAlignmentFromFlags(flags); + const auto x_align = XAlignmentFromFlags(flags); (*render_cache)->text = RenderUTF8_Solid_Wrapped(font, text, text_color, rect.w, x_align); ScaleSurfaceToOutput(&(*render_cache)->text); (*render_cache)->shadow = RenderUTF8_Solid_Wrapped(font, text, shadow_color, rect.w, x_align); diff --git a/SourceX/DiabloUI/title.cpp b/SourceX/DiabloUI/title.cpp index fb73f5b9d..6736db39a 100644 --- a/SourceX/DiabloUI/title.cpp +++ b/SourceX/DiabloUI/title.cpp @@ -4,6 +4,8 @@ namespace dvl { +std::vector vecTitleScreen; + void title_Load() { LoadBackgroundArt("ui_art\\title.pcx"); @@ -14,15 +16,21 @@ void title_Free() { ArtBackground.Unload(); ArtLogos[LOGO_BIG].Unload(); + + for (std::size_t i = 0; i < vecTitleScreen.size(); i++) { + UiItemBase *pUIItem = vecTitleScreen[i]; + delete pUIItem; + } + vecTitleScreen.clear(); } void UiTitleDialog() { - UiItem TITLESCREEN_DIALOG[] = { - MAINMENU_BACKGROUND, - UiImage(&ArtLogos[LOGO_BIG], /*animated=*/true, /*frame=*/0, { 0, 182, 0, 0 }, UIS_CENTER), - UiArtText("Copyright \xA9 1996-2001 Blizzard Entertainment", { PANEL_LEFT + 49, 410, 550, 26 }, UIS_MED | UIS_CENTER) - }; + UiAddBackground(&vecTitleScreen); + UiAddLogo(&vecTitleScreen, LOGO_BIG, 182); + + SDL_Rect rect = { PANEL_LEFT + 49, 410, 550, 26 }; + vecTitleScreen.push_back(new UiArtText("Copyright \xA9 1996-2001 Blizzard Entertainment", rect, UIS_MED | UIS_CENTER)); title_Load(); @@ -31,7 +39,7 @@ void UiTitleDialog() SDL_Event event; while (!endMenu && SDL_GetTicks() < timeOut) { - UiRenderItems(TITLESCREEN_DIALOG, size(TITLESCREEN_DIALOG)); + UiRenderItems(vecTitleScreen); UiFadeIn(); while (SDL_PollEvent(&event)) { diff --git a/SourceX/DiabloUI/ttf_render_wrapped.cpp b/SourceX/DiabloUI/ttf_render_wrapped.cpp index 18351ce27..8630ae97b 100644 --- a/SourceX/DiabloUI/ttf_render_wrapped.cpp +++ b/SourceX/DiabloUI/ttf_render_wrapped.cpp @@ -19,7 +19,7 @@ SDL_bool CharacterIsDelimiter(char c, const char *delimiters) } // namespace // Based on SDL 2.0.12 TTF_RenderUTF8_Blended_Wrapped -SDL_Surface *RenderUTF8_Solid_Wrapped(TTF_Font *font, const char *text, SDL_Color fg, Uint32 wrapLength, TextAlignment x_align) +SDL_Surface *RenderUTF8_Solid_Wrapped(TTF_Font *font, const char *text, SDL_Color fg, Uint32 wrapLength, const int x_align) { int width, height; SDL_Surface *textbuf; @@ -149,6 +149,7 @@ SDL_Surface *RenderUTF8_Solid_Wrapped(TTF_Font *font, const char *text, SDL_Colo SDL_stack_free(str); return NULL; } + dest.w = static_cast(tmp->w); dest.h = static_cast(tmp->h); diff --git a/SourceX/DiabloUI/ttf_render_wrapped.h b/SourceX/DiabloUI/ttf_render_wrapped.h index 2ba52cbb0..3e2092364 100644 --- a/SourceX/DiabloUI/ttf_render_wrapped.h +++ b/SourceX/DiabloUI/ttf_render_wrapped.h @@ -19,6 +19,6 @@ enum TextAlignment { * This method is slow. Caching the result is recommended. */ SDL_Surface *RenderUTF8_Solid_Wrapped( - TTF_Font *font, const char *text, SDL_Color fg, Uint32 wrapLength, TextAlignment x_align = TextAlignment_BEGIN); + TTF_Font *font, const char *text, SDL_Color fg, Uint32 wrapLength, const int x_align = TextAlignment_BEGIN); } // namespace dvl diff --git a/SourceX/DiabloUI/ui_item.h b/SourceX/DiabloUI/ui_item.h index 7a57e96c0..ad445b309 100644 --- a/SourceX/DiabloUI/ui_item.h +++ b/SourceX/DiabloUI/ui_item.h @@ -38,316 +38,314 @@ enum UiFlags { UIS_HIDDEN = 1 << 10, }; -struct UiItemBase { - constexpr UiItemBase(SDL_Rect rect, int flags) - : rect(rect) - , flags(flags) +class UiItemBase { +public: + UiItemBase(SDL_Rect rect, int flags) { - } + m_rect = rect; + m_iFlags = flags; + }; + + UiItemBase(Sint16 x, Sint16 y, Uint16 item_width, Uint16 item_height, int flags) + { + SDL_Rect tmp; + tmp.x = x; + tmp.y = y; + tmp.w = item_width; + tmp.h = item_height; + + m_rect = tmp; + m_iFlags = flags; + }; + + virtual ~UiItemBase() {}; bool has_flag(UiFlags flag) const { - return flags & flag; + return m_iFlags & flag; } bool has_any_flag(int flags) const { - return (this->flags & flags) != 0; + return (m_iFlags & flags) != 0; } void add_flag(UiFlags flag) { - flags |= flag; + m_iFlags |= flag; } void remove_flag(UiFlags flag) { - flags &= ~flag; + m_iFlags &= ~flag; } - SDL_Rect rect; - int flags; + //protected: + UiType m_type; + SDL_Rect m_rect; + int m_iFlags; }; -struct UiImage : public UiItemBase { - constexpr UiImage(Art *art, bool animated, int frame, SDL_Rect rect, int flags = 0) +//============================================================================= + +class UiImage : public UiItemBase { +public: + UiImage(Art *art, SDL_Rect rect, int flags = 0) : UiItemBase(rect, flags) - , art(art) - , animated(animated) - , frame(frame) { - } + m_type = UI_IMAGE; + m_art = art; + m_animated = false; + m_frame = 0; + }; - constexpr UiImage(Art *art, int frame, SDL_Rect rect, int flags = 0) - : UiImage(art, /*animated=*/false, frame, rect, flags) + UiImage(Art *art, bool bAnimated, int iFrame, SDL_Rect rect, int flags) + : UiItemBase(rect, flags) { - } + m_type = UI_IMAGE; + m_art = art; + m_animated = bAnimated; + m_frame = iFrame; + }; - constexpr UiImage(Art *art, SDL_Rect rect, int flags = 0) - : UiImage(art, /*frame=*/0, rect, flags) + UiImage(Art *art, int frame, SDL_Rect rect, int flags = 0) + : UiItemBase(rect, flags) { + m_type = UI_IMAGE; + m_art = art; + m_animated = false; + m_frame = frame; } - Art *art; - bool animated; - int frame; + ~UiImage() {}; + + //private: + Art *m_art; + bool m_animated; + int m_frame; }; -// Plain text (TTF). -struct UiText : public UiItemBase { - constexpr UiText(const char *text, SDL_Color color, SDL_Rect rect, int flags = 0) - : UiItemBase(rect, flags) - , color(color) - , shadow_color { 0, 0, 0, 0 } - , text(text) - , render_cache(NULL) - { - } +//============================================================================= - constexpr UiText(const char *text, SDL_Rect rect, int flags = 0) - : UiText(text, SDL_Color { 243, 243, 243, 0 }, rect, flags) +class UiArtText : public UiItemBase { +public: + UiArtText(const char *text, SDL_Rect rect, int flags = 0) + : UiItemBase(rect, flags) { - } - - SDL_Color color; - SDL_Color shadow_color; - const char *text; + m_type = UI_ART_TEXT; + m_text = text; + }; - // State: - TtfSurfaceCache *render_cache; + ~UiArtText() {}; - void FreeCache() - { - delete render_cache; - render_cache = NULL; - } + //private: + const char *m_text; }; -// Text drawn with Diablo sprites. -struct UiArtText : public UiItemBase { - constexpr UiArtText(const char *text, SDL_Rect rect, int flags = 0) +//============================================================================= + +class UiScrollBar : public UiItemBase { +public: + UiScrollBar(Art *bg, Art *thumb, Art *arrow, SDL_Rect rect, int flags = 0) : UiItemBase(rect, flags) - , text(text) { - } + m_type = UI_SCROLLBAR; + m_bg = bg; + m_thumb = thumb; + m_arrow = arrow; + }; - const char *text; + //private: + Art *m_bg; + Art *m_thumb; + Art *m_arrow; }; -// Clickable Diablo sprites text. -struct UiArtTextButton : public UiItemBase { - constexpr UiArtTextButton(const char *text, void (*action)(), SDL_Rect rect, int flags = 0) +//============================================================================= + +class UiArtTextButton : public UiItemBase { +public: + UiArtTextButton(const char *text, void (*action)(), SDL_Rect rect, int flags = 0) : UiItemBase(rect, flags) - , text(text) - , action(action) { - } - - const char *text; - void (*action)(); + m_type = UI_ART_TEXT_BUTTON; + m_text = text; + m_action = action; + }; + //private: + const char *m_text; + void (*m_action)(); }; -// A button (uses Diablo sprites). -struct UiButton : public UiItemBase { - enum FrameKey { - DEFAULT = 0, - PRESSED, - DISABLED - }; +//============================================================================= - constexpr UiButton(Art *art, const char *text, void (*action)(), SDL_Rect rect, int flags = 0) +class UiEdit : public UiItemBase { +public: + UiEdit(char *value, std::size_t max_length, SDL_Rect rect, int flags = 0) : UiItemBase(rect, flags) - , art(art) - , text(text) - , action(action) - , pressed(false) - , render_cache(NULL) { + m_type = UI_EDIT; + m_value = value; + m_max_length = max_length; } - Art *art; + //private: + char *m_value; + std::size_t m_max_length; +}; - const char *text; - void (*action)(); +//============================================================================= - // State - bool pressed; - TtfSurfaceCache *render_cache; +// Plain text (TTF) - void FreeCache() +class UiText : public UiItemBase { +public: + UiText(const char *text, SDL_Color color1, SDL_Rect rect, int flags = 0) + : UiItemBase(rect, flags) { - delete render_cache; - render_cache = NULL; - } -}; + m_type = UI_TEXT; + m_color = color1; -struct UiListItem { - constexpr UiListItem(const char *text = "", int value = 0) - : text(text) - , value(value) - { + SDL_Color color2 = { 0, 0, 0, 0 }; + m_shadow_color = color2; + + m_text = text; + m_render_cache = NULL; } - const char *text; - int value; -}; -struct UiList : public UiItemBase { - template - constexpr UiList( - UiListItem (&items)[N], - Sint16 x, - Sint16 y, - Uint16 item_width, - Uint16 item_height, - int flags) - : UiItemBase({ x, y, item_width, static_cast(item_height * N) }, flags) - , x(x) - , y(y) - , item_width(item_width) - , item_height(item_height) - , items(items) - , length(N) + UiText(const char *text, SDL_Rect rect, int flags = 0) + : UiItemBase(rect, flags) { - } + m_type = UI_TEXT; - Sint16 x; - Sint16 y; - Uint16 item_width; - Uint16 item_height; - UiListItem *items; - std::size_t length; + SDL_Color color1 = { 243, 243, 243, 0 }; + m_color = color1; - SDL_Rect itemRect(std::size_t i) const - { - return { x, static_cast(y + item_height * i), item_width, item_height }; + SDL_Color color2 = { 0, 0, 0, 0 }; + m_shadow_color = color2; + + m_text = text; + m_render_cache = NULL; } - UiListItem *itemAt(Sint16 y) const + //private: + SDL_Color m_color; + SDL_Color m_shadow_color; + const char *m_text; + + // State: + TtfSurfaceCache *m_render_cache; + + virtual void FreeCache() { - ASSERT(y >= rect.y); - const std::size_t index = (y - rect.y) / item_height; - ASSERT(index < length); - return &items[index]; + delete m_render_cache; + m_render_cache = NULL; } }; -struct UiScrollBar : public UiItemBase { - constexpr UiScrollBar(Art *bg, Art *thumb, Art *arrow, SDL_Rect rect, int flags = 0) - : UiItemBase(rect, flags) - , bg(bg) - , thumb(thumb) - , arrow(arrow) - { - } +//============================================================================= - Art *bg; - Art *thumb; - Art *arrow; -}; +// A button (uses Diablo sprites) -struct UiEdit : public UiItemBase { - constexpr UiEdit(char *value, std::size_t max_length, SDL_Rect rect, int flags) +class UiButton : public UiItemBase { +public: + UiButton(Art *art, const char *text, void (*action)(), SDL_Rect rect, int flags = 0) : UiItemBase(rect, flags) - , value(value) - , max_length(max_length) - { + m_type = UI_BUTTON; + m_art = art; + m_text = text; + m_action = action; + m_pressed = false; + m_render_cache = NULL; } - char *value; - std::size_t max_length; -}; + enum FrameKey { + DEFAULT = 0, + PRESSED, + DISABLED + }; -struct UiItem { - constexpr UiItem(UiText text) - : type(UI_TEXT) - , text(text) - { - } + //private: + Art *m_art; - constexpr UiItem(UiArtText text) - : type(UI_ART_TEXT) - , art_text(text) - { - } + const char *m_text; + void (*m_action)(); - constexpr UiItem(UiArtTextButton art_text_button) - : type(UI_ART_TEXT_BUTTON) - , art_text_button(art_text_button) - { - } + // State + bool m_pressed; + TtfSurfaceCache *m_render_cache; - constexpr UiItem(UiImage image) - : type(UI_IMAGE) - , image(image) + virtual void FreeCache() { + delete m_render_cache; + m_render_cache = NULL; } +}; - constexpr UiItem(UiButton button) - : type(UI_BUTTON) - , button(button) - { - } +//============================================================================= - constexpr UiItem(UiList list) - : type(UI_LIST) - , list(list) +class UiListItem { +public: + UiListItem(const char *text = "", int value = 0) { + m_text = text; + m_value = value; } - constexpr UiItem(UiScrollBar scrollbar) - : type(UI_SCROLLBAR) - , scrollbar(scrollbar) + ~UiListItem() { } - constexpr UiItem(UiEdit edit) - : type(UI_EDIT) - , edit(edit) - { - } + //private: + const char *m_text; + int m_value; +}; - UiType type; - union { - UiText text; - UiArtText art_text; - UiImage image; - UiArtTextButton art_text_button; - UiButton button; - UiList list; - UiScrollBar scrollbar; - UiEdit edit; - UiItemBase common; - }; +typedef std::vector vUiListItem; - bool has_flag(UiFlags flag) const +class UiList : public UiItemBase { +public: + UiList(vUiListItem vItems, Sint16 x, Sint16 y, Uint16 item_width, Uint16 item_height, int flags = 0) + : UiItemBase(x, y, item_width, item_height * vItems.size(), flags) { - return common.has_flag(flag); - } + m_type = UI_LIST; + m_vecItems = vItems; + m_x = x; + m_y = y; + m_width = item_width; + m_height = item_height; + }; - bool has_any_flag(int flags) const + ~UiList() {}; + + SDL_Rect itemRect(int i) const { - return common.has_any_flag(flags); + SDL_Rect tmp; + tmp.x = m_x; + tmp.y = m_y + m_height * i; + tmp.w = m_width; + tmp.h = m_height; + + return tmp; } - const SDL_Rect &rect() const + UiListItem *itemAt(Sint16 y) const { - return common.rect; + ASSERT(y >= m_rect.y); + const std::size_t index = (y - m_rect.y) / m_height; + ASSERT(index < m_vecItems.size()); + return m_vecItems[index]; } - void FreeCache() + UiListItem *GetItem(int i) const { - switch (type) { - case UI_BUTTON: - button.FreeCache(); - break; - case UI_TEXT: - text.FreeCache(); - break; - default: - break; - } + return m_vecItems[i]; } -}; + //private: + Sint16 m_x, m_y; + Uint16 m_width, m_height; + std::vector m_vecItems; +}; } // namespace dvl diff --git a/SourceX/platform/switch/keyboard.cpp b/SourceX/platform/switch/keyboard.cpp index e4e33e0ca..f08d1089c 100644 --- a/SourceX/platform/switch/keyboard.cpp +++ b/SourceX/platform/switch/keyboard.cpp @@ -7,73 +7,73 @@ static void switch_keyboard_get(const char *guide_text, char *initial_text, int max_len, int multiline, char *buf) { - Result rc = 0; + Result rc = 0; - SwkbdConfig kbd; + SwkbdConfig kbd; - rc = swkbdCreate(&kbd, 0); + rc = swkbdCreate(&kbd, 0); - if (R_SUCCEEDED(rc)) { - swkbdConfigMakePresetDefault(&kbd); - swkbdConfigSetGuideText(&kbd, guide_text); - swkbdConfigSetInitialText(&kbd, initial_text); - swkbdConfigSetStringLenMax(&kbd, max_len); - rc = swkbdShow(&kbd, buf, max_len); - swkbdClose(&kbd); - } + if (R_SUCCEEDED(rc)) { + swkbdConfigMakePresetDefault(&kbd); + swkbdConfigSetGuideText(&kbd, guide_text); + swkbdConfigSetInitialText(&kbd, initial_text); + swkbdConfigSetStringLenMax(&kbd, max_len); + rc = swkbdShow(&kbd, buf, max_len); + swkbdClose(&kbd); + } } static int get_utf8_character_bytes(const uint8_t *uc) { - if (uc[0] < 0x80) { - return 1; - } else if ((uc[0] & 0xe0) == 0xc0 && (uc[1] & 0xc0) == 0x80) { - return 2; - } else if ((uc[0] & 0xf0) == 0xe0 && (uc[1] & 0xc0) == 0x80 && (uc[2] & 0xc0) == 0x80) { - return 3; - } else if ((uc[0] & 0xf8) == 0xf0 && (uc[1] & 0xc0) == 0x80 && (uc[2] & 0xc0) == 0x80 && (uc[3] & 0xc0) == 0x80) { - return 4; - } else { - return 1; - } + if (uc[0] < 0x80) { + return 1; + } else if ((uc[0] & 0xe0) == 0xc0 && (uc[1] & 0xc0) == 0x80) { + return 2; + } else if ((uc[0] & 0xf0) == 0xe0 && (uc[1] & 0xc0) == 0x80 && (uc[2] & 0xc0) == 0x80) { + return 3; + } else if ((uc[0] & 0xf8) == 0xf0 && (uc[1] & 0xc0) == 0x80 && (uc[2] & 0xc0) == 0x80 && (uc[3] & 0xc0) == 0x80) { + return 4; + } else { + return 1; + } } static void switch_create_and_push_sdlkey_event(uint32_t event_type, SDL_Scancode scan, SDL_Keycode key) { - SDL_Event event; - event.type = event_type; - event.key.keysym.scancode = scan; - event.key.keysym.sym = key; - event.key.keysym.mod = 0; - SDL_PushEvent(&event); + SDL_Event event; + event.type = event_type; + event.key.keysym.scancode = scan; + event.key.keysym.sym = key; + event.key.keysym.mod = 0; + SDL_PushEvent(&event); } -void switch_start_text_input(const char *guide_text, char *initial_text, int multiline) +void switch_start_text_input(const char *guide_text, char *initial_text, int max_length, int multiline) { - char text[65] = {'\0'}; - switch_keyboard_get(guide_text, initial_text, 64, multiline, text); - for (int i = 0; i < 600; i++) { - switch_create_and_push_sdlkey_event(SDL_KEYDOWN, SDL_SCANCODE_BACKSPACE, SDLK_BACKSPACE); - switch_create_and_push_sdlkey_event(SDL_KEYUP, SDL_SCANCODE_BACKSPACE, SDLK_BACKSPACE); - } - for (int i = 0; i < 600; i++) { - switch_create_and_push_sdlkey_event(SDL_KEYDOWN, SDL_SCANCODE_DELETE, SDLK_DELETE); - switch_create_and_push_sdlkey_event(SDL_KEYUP, SDL_SCANCODE_DELETE, SDLK_DELETE); - } - if (text[0] == '\0') { - strncpy(text, initial_text, 63); - text[64] = {'\0'}; - } - const uint8_t *utf8_text = (uint8_t*) text; - for (int i = 0; i < 599 && utf8_text[i];) { - int bytes_in_char = get_utf8_character_bytes(&utf8_text[i]); - SDL_Event textinput_event; - textinput_event.type = SDL_TEXTINPUT; - for (int n = 0; n < bytes_in_char; n++) { - textinput_event.text.text[n] = text[i + n]; - } - textinput_event.text.text[bytes_in_char] = 0; - SDL_PushEvent(&textinput_event); - i += bytes_in_char; - } + char text[max_length] = { '\0' }; + switch_keyboard_get(guide_text, initial_text, max_length, multiline, text); + for (int i = 0; i < 600; i++) { + switch_create_and_push_sdlkey_event(SDL_KEYDOWN, SDL_SCANCODE_BACKSPACE, SDLK_BACKSPACE); + switch_create_and_push_sdlkey_event(SDL_KEYUP, SDL_SCANCODE_BACKSPACE, SDLK_BACKSPACE); + } + for (int i = 0; i < 600; i++) { + switch_create_and_push_sdlkey_event(SDL_KEYDOWN, SDL_SCANCODE_DELETE, SDLK_DELETE); + switch_create_and_push_sdlkey_event(SDL_KEYUP, SDL_SCANCODE_DELETE, SDLK_DELETE); + } + if (text[0] == '\0') { + strncpy(text, initial_text, max_length - 1); + text[max_length] = { '\0' }; + } + const uint8_t *utf8_text = (uint8_t *)text; + for (int i = 0; i < 599 && utf8_text[i];) { + int bytes_in_char = get_utf8_character_bytes(&utf8_text[i]); + SDL_Event textinput_event; + textinput_event.type = SDL_TEXTINPUT; + for (int n = 0; n < bytes_in_char; n++) { + textinput_event.text.text[n] = text[i + n]; + } + textinput_event.text.text[bytes_in_char] = 0; + SDL_PushEvent(&textinput_event); + i += bytes_in_char; + } } diff --git a/SourceX/platform/switch/keyboard.h b/SourceX/platform/switch/keyboard.h index 5ab737913..3f076c557 100644 --- a/SourceX/platform/switch/keyboard.h +++ b/SourceX/platform/switch/keyboard.h @@ -1,3 +1,3 @@ #pragma once -void switch_start_text_input(const char *guide_text, char *initial_text, int multiline); +void switch_start_text_input(const char *guide_text, char *initial_text, int max_length, int multiline);