MU Online - S6.3 - Layout Resize real time - Source Mu - Mu Server Files
 

Noticias:

SMF - Just Installed!

Menú principal

MU Online - S6.3 - Layout Resize real time

Publicado por Dakosmu, Nov 06, 2025, 03:46 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Dakosmu

MU Online - S6.3 - Layout Redimensionable en Tiempo Real

Descripción General

Esta guía paso a paso explica cómo implementar la función de redimensionamiento en tiempo real (Layout Resize real time) en un cliente de MU Online S6.3, permitiendo a los usuarios cambiar el tamaño y la posición de la ventana del panel.

---
Video Demostrativo

Regístrate para ver el enlace

---
Vista Previa



---
Archivos y Modificaciones

1. Modificación en Interface.cpp

Abre el archivo Interface.cpp y busca la función void Interface::Work().

Reemplaza el código existente dentro de la función con el siguiente:

void Interface::Work()
{
    gLayout.UpdateLayoutPanelWindow();
    gLayout.DrawLayoutPanelWindow();
}

---
2. Modificación en Layout.cpp

Abre el archivo Layout.cpp y asegúrate de incluir los encabezados necesarios.

Busca y reemplaza o inserta las funciones y variables de la clase CLayout según el siguiente código. Este código maneja la lógica de arrastrar (drag), redimensionar (resize), el control de las páginas internas, y la detección de la tecla F4 para mostrar/ocultar.

#include "stdafx.h"
#include "layout.h"
#include "Interface.h"
#include "Central.h"
#include "Defines.h"
#include "Import.h"
#include "CustomFont.h"
#include "Defines2.h"
#include <vector>
#include <string>
#include <fstream>
#include <windows.h> // Para DWORD, GetTickCount(), VK_F4, etc.
#include <cstdarg> // Para va_start e va_end

// Inicializa o gLayout e as variáveis de drag dentro da classe
CLayout::CLayout()
{
    // Construtor vazio. Caso necessite, adicione inicializações aqui.
}

CLayout gLayout;

void CLayout::UpdateLayoutPanelWindow()
{
    // Variável estática para controlar o estado da tecla F4
    static bool isF4Pressed = false;
    bool currentF4State = (GetAsyncKeyState(VK_F4) & 0x8000) != 0;

    if (currentF4State && !isF4Pressed)
    {
        // Alterna a flag de exibição do painel
        gInterface.Data[eLayout_MAIN].OnShow = !gInterface.Data[eLayout_MAIN].OnShow;

        // Adiciona o som ao abrir ou fechar com F4
        PlayBuffer(25, 0, 0);

        isF4Pressed = true;
    }
    else if (!currentF4State)
    {
        isF4Pressed = false;
    }
}

int CLayout::DrawToolTip(int X, int Y, LPCSTR Text, ...)
{
    // Como estamos tendo problemas com va_start/va_end, vamos usar uma solução mais simples
    // Definir diretamente a cor do texto para branco antes de chamar pDrawToolTip
    pSetTextColor(pTextThis(), 255, 255, 255, 255); // Branco brilhante
   
    // Desenha o tooltip diretamente com o texto fornecido
    int result = pDrawToolTip(X, Y, Text);
   
    return result;
}

// Variáveis globais para controle de páginas
int currentPage = 0;
int maxPages = 5; // Número total de páginas disponíveis
DWORD lastButtonClickTime = 0; // Tempo do último clique nos botões
const DWORD clickDelay = 300; // Delay entre cliques em milissegundos

// Variáveis globais para controle do drag e da posição/tamanho do painel
bool    m_isDragging = false;
POINT  m_dragStartPoint;
float m_windowPosX = (MAX_WIN_WIDTH - 230.0f) / 2;
float m_windowPosY = (MAX_WIN_HEIGHT - 240.0f) / 2;
float m_windowWidth = 230.0f;
float m_windowHeight = 240.0f;

// Variáveis globais para redimensionamento via ícone no topo esquerdo
bool    m_isResizingPanel = false;
POINT  m_resizeStartPoint;
float m_initialPosX = 0.0f;
float m_initialPosY = 0.0f;
float m_initialWidth = 0.0f;
float m_initialHeight = 0.0f;

// Variável para controlar o tempo do último clique no botão de menu
DWORD lastMenuButtonClickTime = 0;
const DWORD menuClickDelay = 300; // Delay entre cliques em milissegundos

// Variável para controlar o tempo do último clique no botão de opções
DWORD lastOptionButtonClickTime = 0;
const DWORD optionClickDelay = 300; // Delay entre cliques em milissegundos

// ID do objeto de interface para o botão de menu
short eLayoutButtonMenu = 12350; // Usando um ID não usado
// ID do objeto de interface para o botão de opções
short eLayoutButtonOption = 12351; // Usando um ID não usado

void CLayout::DrawLayoutPanelWindow()
{
    // Se o painel não estiver para ser exibido, sai da função
    if (!gInterface.Data[eLayout_MAIN].OnShow)
        return;

    // Garante o foco do cursor
    pSetCursorFocus = true;

    // Variáveis para controle de clique e tempo
    bool isLeftButtonDown = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
    DWORD currentTime = GetTickCount();

    // Dimensões atuais do painel (variáveis para permitir redimensionamento)
    float MainWidth = m_windowWidth;
    float MainHeight = m_windowHeight;

    // Define a posição base para o texto (precisa ser definida antes para calcular posições dos botões)
    float StartX = m_windowPosX;
    float StartY = m_windowPosY;

    // Calcula posições dos elementos interativos antes da lógica de drag
    bool isOverInteractiveElement = false;
   
    // Ícone de redimensionar (lado esquerdo superior) — menor e dentro do layout
    const float resizeIconW = 14.0f;
    const float resizeIconH = 14.0f;
    float resizeIconX = m_windowPosX + 4.0f;
    float resizeIconY = m_windowPosY + 4.0f;
    bool overResizeIcon = pCheckMouseOver(resizeIconX, resizeIconY, resizeIconW, resizeIconH);
   
    // Verifica botão de fechar
    float closeButtonX = m_windowPosX + MainWidth - 20;
    float closeButtonY = m_windowPosY - 10;
    if (pCheckMouseOver(closeButtonX, closeButtonY, 36, 29))
    {
        isOverInteractiveElement = true;
    }
    if (overResizeIcon)
    {
        isOverInteractiveElement = true;
    }
   
    // Verifica botões de navegação
    float buttonWidth = 20.0f;
    float buttonHeight = 20.0f;
    float backButtonX = m_windowPosX + 10.0f;
    float backButtonY = m_windowPosY + MainHeight - 30.0f;
    float forwardButtonX = m_windowPosX + MainWidth - 30.0f;
    float forwardButtonY = m_windowPosY + MainHeight - 30.0f;
   
    if (currentPage > 0 && pCheckMouseOver(backButtonX, backButtonY, buttonWidth, buttonHeight))
    {
        isOverInteractiveElement = true;
    }
    if (currentPage < maxPages - 1 && pCheckMouseOver(forwardButtonX, forwardButtonY, buttonWidth, buttonHeight))
    {
        isOverInteractiveElement = true;
    }
   
    // Verifica botões de menu e opções (apenas na página 5)
    if (currentPage == 4)
    {
        float menuButtonWidth = 107.1f;
        float menuButtonHeight = 29.0f;
        float menuButtonX = m_windowPosX + (MainWidth / 2) - (menuButtonWidth / 2);
        float menuButtonY = m_windowPosY + 5.0f;
       
        float optionButtonWidth = 107.1f;
        float optionButtonHeight = 29.0f;
        float optionButtonX = m_windowPosX + (MainWidth / 2) - (optionButtonWidth / 2);
        float optionButtonY = menuButtonY + menuButtonHeight + 5.0f;
       
        if (pCheckMouseOver(menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight) ||
            pCheckMouseOver(optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight))
        {
            isOverInteractiveElement = true;
        }
    }

    // Lógica de redimensionamento (prioritária sobre drag)
    if (m_isResizingPanel)
    {
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
        {
            float deltaX = pCursorX - m_resizeStartPoint.x;
            float deltaY = pCursorY - m_resizeStartPoint.y;

            // Ancorado no canto inferior-direito, arrastando o topo-esquerdo
            float newPosX = m_initialPosX + deltaX;
            float newPosY = m_initialPosY + deltaY;
            float newWidth = m_initialWidth - deltaX;
            float newHeight = m_initialHeight - deltaY;

            // Mínimos
            const float minW = 180.0f;
            const float minH = 140.0f;

            if (newWidth < minW)
            {
                // Corrige posição para manter a borda direita estável
                newPosX -= (minW - newWidth);
                newWidth = minW;
            }
            if (newHeight < minH)
            {
                newPosY -= (minH - newHeight);
                newHeight = minH;
            }

            // Límites da tela (painel deve ficar visível)
            if (newPosX < 0.0f)
            {
                // Ao sair pela esquerda, ajusta largura e posição
                float excess = -newPosX;
                newPosX = 0.0f;
                newWidth += excess;
            }
            if (newPosY < 0.0f)
            {
                float excess = -newPosY;
                newPosY = 0.0f;
                newHeight += excess;
            }
            if (newPosX + newWidth > MAX_WIN_WIDTH)
            {
                newWidth = MAX_WIN_WIDTH - newPosX;
            }
            if (newPosY + newHeight > MAX_WIN_HEIGHT)
            {
                newHeight = MAX_WIN_HEIGHT - newPosY;
            }

            // Aplica
            m_windowPosX = newPosX;
            m_windowPosY = newPosY;
            m_windowWidth = newWidth;
            m_windowHeight = newHeight;

            // Atualiza cópias locais usadas no desenho
            MainWidth = m_windowWidth;
            MainHeight = m_windowHeight;
        }
        else
        {
            m_isResizingPanel = false;
        }
    }
    else if (overResizeIcon && (GetAsyncKeyState(VK_LBUTTON) & 0x8000))
    {
        // Inicia redimensionamento
        m_isResizingPanel = true;
        m_resizeStartPoint.x = pCursorX;
        m_resizeStartPoint.y = pCursorY;
        m_initialPosX = m_windowPosX;
        m_initialPosY = m_windowPosY;
        m_initialWidth = m_windowWidth;
        m_initialHeight = m_windowHeight;
        PlayBuffer(25, 0, 0);
    }

    // Lógica para drag and drop
    // Se já estiver arrastando, continua arrastando mesmo sobre elementos interativos
    if (!m_isResizingPanel && m_isDragging)
    {
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
        {
            float deltaX = pCursorX - m_dragStartPoint.x;
            float deltaY = pCursorY - m_dragStartPoint.y;

            m_windowPosX += deltaX;
            m_windowPosY += deltaY;

            if (m_windowPosX < 0)
                m_windowPosX = 0;
            else if (m_windowPosX > MAX_WIN_WIDTH - MainWidth)
                m_windowPosX = MAX_WIN_WIDTH - MainWidth;

            if (m_windowPosY < 0)
                m_windowPosY = 0;
            else if (m_windowPosY > MAX_WIN_HEIGHT - MainHeight)
                m_windowPosY = MAX_WIN_HEIGHT - MainHeight;

            m_dragStartPoint.x = pCursorX;
            m_dragStartPoint.y = pCursorY;
        }
        else
        {
            m_isDragging = false;
        }
    }
    // Se não estiver arrastando, verifica se pode iniciar el drag
    else if (!m_isResizingPanel && pCheckMouseOver(m_windowPosX, m_windowPosY, MainWidth, MainHeight))
    {
        // Sólo inicia el drag si no está sobre un elemento interactivo
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000 && !isOverInteractiveElement)
        {
            m_isDragging = true;
            m_dragStartPoint.x = pCursorX;
            m_dragStartPoint.y = pCursorY;
        }
    }

    // Dibuja el panel flotante en la posición actual
    gCentral.PrintDropBox(m_windowPosX, m_windowPosY, MainWidth, MainHeight, 0, 0);
   
    // Dibuja el ícono de redimensionar (izquierda superior)
    if (overResizeIcon)
    {
        pDrawButton(0x7A5E, resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0, (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ? 58 : 29);
        // Capa semitransparente para dar apariencia "medio transparente"
        gInterface.DrawBarForm(resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0.0f, 0.0f, 0.0f, 0.45f);
        this->DrawToolTip(resizeIconX + 5, resizeIconY + 25, "Redimensionar");
    }
    else
    {
        pDrawButton(0x7A5E, resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0, 0);
        // Capa semitransparente para dar apariencia "medio transparente"
        gInterface.DrawBarForm(resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0.0f, 0.0f, 0.0f, 0.45f);
    }
   
    // Actualiza StartX y StartY después de posible movimiento del drag
    StartX = m_windowPosX;
    StartY = m_windowPosY;

    // --- Botón de menú ---
    // Mostrar el botón sólo en la página 5 (índice 4)
    if (currentPage == 4)
    {
        // Definiendo las dimensiones y posición del botón menu (ya calculadas arriba)
        float menuButtonWidth = 107.1f; // Misma largura del botón Menu Option
        float menuButtonHeight = 29.0f; // Misma altura del botón Menu Option
        float menuButtonX = StartX + (MainWidth / 2) - (menuButtonWidth / 2);
        float menuButtonY = StartY + 5.0f; // Posicionado más arriba

        // Vinculando el objeto de botón de menu (apenas una vez)
        static bool buttonBound = false;
        if (!buttonBound) {
            gInterface.BindObject(eLayoutButtonMenu, 0x7A5E, menuButtonWidth, menuButtonHeight, -1, -1);
            gInterface.BindObject(eLayoutButtonOption, 0x7A5E, menuButtonWidth, menuButtonHeight, -1, -1);
            buttonBound = true;
        }

        // Dibujando el botón del menu
        bool isHovered = pCheckMouseOver(menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight);

        // Verificando si está sobre el botón
        if (isHovered)
        {
            if (isLeftButtonDown && (currentTime - lastMenuButtonClickTime > menuClickDelay))
            {
                // Dibujando el botón con estilo de clic
                pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 58);

                // Marca el tiempo del clic
                lastMenuButtonClickTime = currentTime;

                // Reproduce sonido al clicar
                PlayBuffer(25, 0, 0);

                // Cierra el panel de layout
                //gInterface.Data[eLayout_MAIN].OnShow = false;

                // aqui abre menu option
                //if (!gInterface.CheckMenuWindow())
                //{
                //    gInterface.CloseCustomWindow();
                //    gInterface.OpenMenuWindow();
                //}
            }
            else
            {
                // Dibujando el botón con estilo de hover
                pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 29);
                this->DrawToolTip(menuButtonX + 5, menuButtonY - 15, "Abrir Menu");
            }
        }
        else
        {
            // Dibujando el botón normal
            pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 0);
        }

        // Dibuja el texto "MENU" en el botón
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define la cor del texto como blanco brillante
        gInterface.DrawFormat(eWhite, menuButtonX, menuButtonY + 9, menuButtonWidth, 3, "MENU");

        // ----- Botón Option -----
        // Posicionando el botón Option debajo del botón Menu (ya calculadas arriba)
        float optionButtonWidth = 107.1f;
        float optionButtonHeight = 29.0f;
        float optionButtonX = StartX + (MainWidth / 2) - (optionButtonWidth / 2);
        float optionButtonY = menuButtonY + menuButtonHeight + 5.0f; // 5 pixels debajo del botón menu

        // Dibujando el botón de opciones
        bool isOptionHovered = pCheckMouseOver(optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight);

        // Verificando si está sobre el botón
        if (isOptionHovered)
        {
            if (isLeftButtonDown && (currentTime - lastOptionButtonClickTime > optionClickDelay))
            {
                // Dibujando el botón con estilo de clic
                pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 58);

                // Marca el tiempo del clic
                lastOptionButtonClickTime = currentTime;

                // Reproduce som ao clicar
                PlayBuffer(25, 0, 0);

                // Aquí puedes adicionar la funcionalidad que deseas cuando el botón for clicado
                // Por ejemplo, abrir una janela de configurações ou opções
                // Por enquanto, apenas fecha o layout como exemplo
                //gInterface.Data[eLayout_MAIN].OnShow = false;
            }
            else
            {
                // Dibujando el botón con estilo de hover
                pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 29);
                this->DrawToolTip(optionButtonX + 5, optionButtonY - 15, "Configurações");
            }
        }
        else
        {
            // Dibujando el botón normal
            pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 0);
        }

        // Dibuja el texto "OPTION" en el botón
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define la cor del texto como blanco brillante
        gInterface.DrawFormat(eWhite, optionButtonX, optionButtonY + 9, optionButtonWidth, 3, "OPTION");
    }

    // Crea vectores de líneas de texto para cada página

    // Página 1
    std::vector<std::string> textos1;
    textos1.push_back("SEJA BEM VINDO AO MUONLINE");
    textos1.push_back("O continente de MU era glorioso e vasto,");
    textos1.push_back("Quando Kundun surgiu, trazendo o caos mortal.");
    textos1.push_back("Heróis lutaram com força e magia.");
    textos1.push_back("Criaturas sombrias espalharam terror.");

    // Página 2
    std::vector<std::string> textos2;
    textos2.push_back("GUIA DE CLASSES");
    textos2.push_back("SM: Mestre da magia elemental.");
    textos2.push_back("BK: Guerreiro poderoso em combate corpo a corpo.");
    textos2.push_back("Elf: Arqueira ágil com habilidades de suporte.");
    textos2.push_back("MG: Híbrido de força física e poderes mágicos.");
    textos2.push_back("as trevas estavam corruptas");

    // Página 3
    std::vector<std::string> textos3;
    textos3.push_back("MAPAS DE MU ONLINE");
    textos3.push_back("Lorencia: Cidade inicial e principal.");
    textos3.push_back("Noria: Lar dos elfos e seres másticos.");
    textos3.push_back("Davias: Deserto habitado por criaturas perigosas.");
    textos3.push_back("Atlans: Reino subaquático de monstros exóticos.");
    textos3.push_back("as vezes podemos alcançar");

    // Página 4
    std::vector<std::string> textos4;
    textos4.push_back("EVENTOS ESPECIAIS");
    textos4.push_back("Blood Castle: Desafie os guardiões.");
    textos4.push_back("Devil Square: Arena de monstros.");
    textos4.push_back("Chaos Castle: Sobreviva contra monstros.");
    textos4.push_back("Golden Invasion: Lute contra monstros dourados.");
    textos4.push_back("venha vamos correr para alcançar");

    // Página 5
    std::vector<std::string> textos5;

    std::vector<std::vector<std::string>> textosPages;
    textosPages.push_back(textos1);
    textosPages.push_back(textos2);
    textosPages.push_back(textos3);
    textosPages.push_back(textos4);
    textosPages.push_back(textos5);

    // Vector con los tamaños (en puntos) padrão para cada línea
    std::vector<int> fontSizes;
    fontSizes.push_back(20);
    fontSizes.push_back(16);
    fontSizes.push_back(16);
    fontSizes.push_back(16);
    fontSizes.push_back(16);

    // Para este ejemplo, las líneas de la página serán siempre desenhadas con "Segoe UI" (o otra fuente caso deseado)
    // Si es necesario utilizar fuentes diferentes para cada línea, cree un vector adicional (vea ejemplos anteriores)

    // Define el espaciamiento vertical entre las líneas (padrão)
    const float linhaAlturaPadrao = 30.0f;
    float linhaAltura = linhaAlturaPadrao;

    // Escoge el texto de la página actual
    std::vector<std::string> textos = textosPages[currentPage];

    // Calcula la posición inicial vertical para centralizar el bl

---
Funcionalidad Clave (Explicación)

Esta modificación permite:

  • Redimensionamiento Draggable: Al hacer clic y arrastrar el pequeño ícono en la esquina superior izquierda, el panel de información (Layout Window) se puede redimensionar en tiempo real.
  • Movimiento (Drag-and-Drop): Al hacer clic en cualquier parte del panel (excepto en los elementos interactivos), se puede arrastrar la ventana a una nueva posición en la pantalla.
  • Límites y Mínimos: El código incluye lógica para evitar que el panel se redimensione o mueva fuera de los límites de la pantalla del juego y asegura un tamaño mínimo para mantener la usabilidad (180x140).
  • Control F4: La tecla F4 se utiliza para alternar la visibilidad del panel (Regístrate para ver el enlace[eLayout_MAIN].OnShow).
---
Archivos de Descarga

Regístrate para ver el enlace

Regístrate para ver el enlace
Bon Dia

Dakosmu

Layout.cpp

#include "stdafx.h"
#include "layout.h"
#include "Interface.h"
#include "Central.h"
#include "Defines.h"
#include "Import.h"
#include "CustomFont.h"
#include "Defines2.h"
#include <vector>
#include <string>
#include <fstream>
#include <windows.h> // Para DWORD, GetTickCount(), VK_F4, etc.
#include <cstdarg> // Para va_start e va_end

// Inicializa o gLayout e as variáveis de drag dentro da classe
CLayout::CLayout()
{
    // Construtor vazio. Caso necessite, adicione inicializações aqui.
}

CLayout gLayout;

void CLayout::UpdateLayoutPanelWindow()
{
    // Variável estática para controlar o estado da tecla F4
    static bool isF4Pressed = false;
    bool currentF4State = (GetAsyncKeyState(VK_F4) & 0x8000) != 0;

    if (currentF4State && !isF4Pressed)
    {
        // Alterna a flag de exibição do painel
        gInterface.Data[eLayout_MAIN].OnShow = !gInterface.Data[eLayout_MAIN].OnShow;

        // Adiciona o som ao abrir ou fechar com F4
        PlayBuffer(25, 0, 0);

        isF4Pressed = true;
    }
    else if (!currentF4State)
    {
        isF4Pressed = false;
    }
}

int CLayout::DrawToolTip(int X, int Y, LPCSTR Text, ...)
{
    // Como estamos tendo problemas com va_start/va_end, vamos usar uma solução mais simples
    // Definir diretamente a cor do texto para branco antes de chamar pDrawToolTip
    pSetTextColor(pTextThis(), 255, 255, 255, 255); // Branco brilhante
   
    // Desenha o tooltip diretamente com o texto fornecido
    int result = pDrawToolTip(X, Y, Text);
   
    return result;
}

// Variáveis globais para controle de páginas
int currentPage = 0;
int maxPages = 5; // Número total de páginas disponíveis
DWORD lastButtonClickTime = 0; // Tempo do último clique nos botões
const DWORD clickDelay = 300; // Delay entre cliques em milissegundos

// Variáveis globais para controle do drag e da posição/tamanho do painel
bool   m_isDragging = false;
POINT  m_dragStartPoint;
float m_windowPosX = (MAX_WIN_WIDTH - 230.0f) / 2;
float m_windowPosY = (MAX_WIN_HEIGHT - 240.0f) / 2;
float m_windowWidth = 230.0f;
float m_windowHeight = 240.0f;

// Variáveis globais para redimensionamento via ícone no topo esquerdo
bool   m_isResizingPanel = false;
POINT  m_resizeStartPoint;
float m_initialPosX = 0.0f;
float m_initialPosY = 0.0f;
float m_initialWidth = 0.0f;
float m_initialHeight = 0.0f;

// Variável para controlar o tempo do último clique no botão de menu
DWORD lastMenuButtonClickTime = 0;
const DWORD menuClickDelay = 300; // Delay entre cliques em milissegundos

// Variável para controlar o tempo do último clique no botão de opções
DWORD lastOptionButtonClickTime = 0;
const DWORD optionClickDelay = 300; // Delay entre cliques em milissegundos

// ID do objeto de interface para o botão de menu
short eLayoutButtonMenu = 12350; // Usando um ID não usado
// ID do objeto de interface para o botão de opções
short eLayoutButtonOption = 12351; // Usando um ID não usado

void CLayout::DrawLayoutPanelWindow()
{
    // Se o painel não estiver para ser exibido, sai da função
    if (!gInterface.Data[eLayout_MAIN].OnShow)
        return;

    // Garante o foco do cursor
    pSetCursorFocus = true;

    // Variáveis para controle de clique e tempo
    bool isLeftButtonDown = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
    DWORD currentTime = GetTickCount();

    // Dimensões atuais do painel (variáveis para permitir redimensionamento)
    float MainWidth = m_windowWidth;
    float MainHeight = m_windowHeight;

    // Define a posição base para o texto (precisa ser definida antes para calcular posições dos botões)
    float StartX = m_windowPosX;
    float StartY = m_windowPosY;

    // Calcula posições dos elementos interativos antes da lógica de drag
    bool isOverInteractiveElement = false;
   
    // Ícone de redimensionar (lado esquerdo superior) — menor e dentro do layout
    const float resizeIconW = 14.0f;
    const float resizeIconH = 14.0f;
    float resizeIconX = m_windowPosX + 4.0f;
    float resizeIconY = m_windowPosY + 4.0f;
    bool overResizeIcon = pCheckMouseOver(resizeIconX, resizeIconY, resizeIconW, resizeIconH);
   
    // Verifica botão de fechar
    float closeButtonX = m_windowPosX + MainWidth - 20;
    float closeButtonY = m_windowPosY - 10;
    if (pCheckMouseOver(closeButtonX, closeButtonY, 36, 29))
    {
        isOverInteractiveElement = true;
    }
    if (overResizeIcon)
    {
        isOverInteractiveElement = true;
    }
   
    // Verifica botões de navegação
    float buttonWidth = 20.0f;
    float buttonHeight = 20.0f;
    float backButtonX = m_windowPosX + 10.0f;
    float backButtonY = m_windowPosY + MainHeight - 30.0f;
    float forwardButtonX = m_windowPosX + MainWidth - 30.0f;
    float forwardButtonY = m_windowPosY + MainHeight - 30.0f;
   
    if (currentPage > 0 && pCheckMouseOver(backButtonX, backButtonY, buttonWidth, buttonHeight))
    {
        isOverInteractiveElement = true;
    }
    if (currentPage < maxPages - 1 && pCheckMouseOver(forwardButtonX, forwardButtonY, buttonWidth, buttonHeight))
    {
        isOverInteractiveElement = true;
    }
   
    // Verifica botões de menu e opções (apenas na página 5)
    if (currentPage == 4)
    {
        float menuButtonWidth = 107.1f;
        float menuButtonHeight = 29.0f;
        float menuButtonX = m_windowPosX + (MainWidth / 2) - (menuButtonWidth / 2);
        float menuButtonY = m_windowPosY + 5.0f;
       
        float optionButtonWidth = 107.1f;
        float optionButtonHeight = 29.0f;
        float optionButtonX = m_windowPosX + (MainWidth / 2) - (optionButtonWidth / 2);
        float optionButtonY = menuButtonY + menuButtonHeight + 5.0f;
       
        if (pCheckMouseOver(menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight) ||
            pCheckMouseOver(optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight))
        {
            isOverInteractiveElement = true;
        }
    }

    // Lógica de redimensionamento (prioritária sobre drag)
    if (m_isResizingPanel)
    {
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
        {
            float deltaX = pCursorX - m_resizeStartPoint.x;
            float deltaY = pCursorY - m_resizeStartPoint.y;

            // Ancorado no canto inferior-direito, arrastando o topo-esquerdo
            float newPosX = m_initialPosX + deltaX;
            float newPosY = m_initialPosY + deltaY;
            float newWidth = m_initialWidth - deltaX;
            float newHeight = m_initialHeight - deltaY;

            // Mínimos
            const float minW = 180.0f;
            const float minH = 140.0f;

            if (newWidth < minW)
            {
                // Corrige posição para manter a borda direita estável
                newPosX -= (minW - newWidth);
                newWidth = minW;
            }
            if (newHeight < minH)
            {
                newPosY -= (minH - newHeight);
                newHeight = minH;
            }

            // Limites da tela (painel deve ficar visível)
            if (newPosX < 0.0f)
            {
                // Ao sair pela esquerda, ajusta largura e posição
                float excess = -newPosX;
                newPosX = 0.0f;
                newWidth += excess;
            }
            if (newPosY < 0.0f)
            {
                float excess = -newPosY;
                newPosY = 0.0f;
                newHeight += excess;
            }
            if (newPosX + newWidth > MAX_WIN_WIDTH)
            {
                newWidth = MAX_WIN_WIDTH - newPosX;
            }
            if (newPosY + newHeight > MAX_WIN_HEIGHT)
            {
                newHeight = MAX_WIN_HEIGHT - newPosY;
            }

            // Aplica
            m_windowPosX = newPosX;
            m_windowPosY = newPosY;
            m_windowWidth = newWidth;
            m_windowHeight = newHeight;

            // Atualiza cópias locais usadas no desenho
            MainWidth = m_windowWidth;
            MainHeight = m_windowHeight;
        }
        else
        {
            m_isResizingPanel = false;
        }
    }
    else if (overResizeIcon && (GetAsyncKeyState(VK_LBUTTON) & 0x8000))
    {
        // Inicia redimensionamento
        m_isResizingPanel = true;
        m_resizeStartPoint.x = pCursorX;
        m_resizeStartPoint.y = pCursorY;
        m_initialPosX = m_windowPosX;
        m_initialPosY = m_windowPosY;
        m_initialWidth = m_windowWidth;
        m_initialHeight = m_windowHeight;
        PlayBuffer(25, 0, 0);
    }

    // Lógica para drag and drop
    // Se já estiver arrastando, continua arrastando mesmo sobre elementos interativos
    if (!m_isResizingPanel && m_isDragging)
    {
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
        {
            float deltaX = pCursorX - m_dragStartPoint.x;
            float deltaY = pCursorY - m_dragStartPoint.y;

            m_windowPosX += deltaX;
            m_windowPosY += deltaY;

            if (m_windowPosX < 0)
                m_windowPosX = 0;
            else if (m_windowPosX > MAX_WIN_WIDTH - MainWidth)
                m_windowPosX = MAX_WIN_WIDTH - MainWidth;

            if (m_windowPosY < 0)
                m_windowPosY = 0;
            else if (m_windowPosY > MAX_WIN_HEIGHT - MainHeight)
                m_windowPosY = MAX_WIN_HEIGHT - MainHeight;

            m_dragStartPoint.x = pCursorX;
            m_dragStartPoint.y = pCursorY;
        }
        else
        {
            m_isDragging = false;
        }
    }
    // Se não estiver arrastando, verifica se pode iniciar o drag
    else if (!m_isResizingPanel && pCheckMouseOver(m_windowPosX, m_windowPosY, MainWidth, MainHeight))
    {
        // Só inicia o drag se não estiver sobre um elemento interativo
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000 && !isOverInteractiveElement)
        {
            m_isDragging = true;
            m_dragStartPoint.x = pCursorX;
            m_dragStartPoint.y = pCursorY;
        }
    }

    // Desenha o painel flutuante na posição atual
    gCentral.PrintDropBox(m_windowPosX, m_windowPosY, MainWidth, MainHeight, 0, 0);
   
    // Desenha o ícone de redimensionar (esquerda superior)
    if (overResizeIcon)
    {
        pDrawButton(0x7A5E, resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0, (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ? 58 : 29);
        // Camada semitransparente para dar aparência "meio transparente"
        gInterface.DrawBarForm(resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0.0f, 0.0f, 0.0f, 0.45f);
        this->DrawToolTip(resizeIconX + 5, resizeIconY + 25, "Redimensionar");
    }
    else
    {
        pDrawButton(0x7A5E, resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0, 0);
        // Camada semitransparente para dar aparência "meio transparente"
        gInterface.DrawBarForm(resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0.0f, 0.0f, 0.0f, 0.45f);
    }
   
    // Atualiza StartX e StartY após possível movimento do drag
    StartX = m_windowPosX;
    StartY = m_windowPosY;

    // --- Botão de menu ---
    // Mostrar o botão apenas na página 5 (índice 4)
    if (currentPage == 4)
    {
        // Definindo as dimensões e posição do botão menu (já calculadas acima)
        float menuButtonWidth = 107.1f; // Mesma largura do botão Menu Option
        float menuButtonHeight = 29.0f; // Mesma altura do botão Menu Option
        float menuButtonX = StartX + (MainWidth / 2) - (menuButtonWidth / 2);
        float menuButtonY = StartY + 5.0f; // Posicionado mais acima

        // Vinculando o objeto de botão de menu (apenas uma vez)
        static bool buttonBound = false;
        if (!buttonBound) {
            gInterface.BindObject(eLayoutButtonMenu, 0x7A5E, menuButtonWidth, menuButtonHeight, -1, -1);
            gInterface.BindObject(eLayoutButtonOption, 0x7A5E, menuButtonWidth, menuButtonHeight, -1, -1);
            buttonBound = true;
        }

        // Desenhando o botão do menu
        bool isHovered = pCheckMouseOver(menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight);

        // Verificando se está sobre o botão
        if (isHovered)
        {
            if (isLeftButtonDown && (currentTime - lastMenuButtonClickTime > menuClickDelay))
            {
                // Desenhando o botão com estilo de clique
                pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 58);

                // Marca o tempo do clique
                lastMenuButtonClickTime = currentTime;

                // Reproduz som ao clicar
                PlayBuffer(25, 0, 0);

                // Fecha o painel de layout
                //gInterface.Data[eLayout_MAIN].OnShow = false;

                // aqui abre menu option
                //if (!gInterface.CheckMenuWindow())
                //{
                //    gInterface.CloseCustomWindow();
                //    gInterface.OpenMenuWindow();
                //}
            }
            else
            {
                // Desenhando o botão com estilo de hover
                pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 29);
                this->DrawToolTip(menuButtonX + 5, menuButtonY - 15, "Abrir Menu");
            }
        }
        else
        {
            // Desenhando o botão normal
            pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 0);
        }

        // Desenha o texto "MENU" no botão
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define a cor do texto como branco brilhante
        gInterface.DrawFormat(eWhite, menuButtonX, menuButtonY + 9, menuButtonWidth, 3, "MENU");

        // ----- Botão Option -----
        // Posicionando o botão Option abaixo do botão Menu (já calculadas acima)
        float optionButtonWidth = 107.1f;
        float optionButtonHeight = 29.0f;
        float optionButtonX = StartX + (MainWidth / 2) - (optionButtonWidth / 2);
        float optionButtonY = menuButtonY + menuButtonHeight + 5.0f; // 5 pixels abaixo do botão menu

        // Desenhando o botão de opções
        bool isOptionHovered = pCheckMouseOver(optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight);

        // Verificando se está sobre o botão
        if (isOptionHovered)
        {
            if (isLeftButtonDown && (currentTime - lastOptionButtonClickTime > optionClickDelay))
            {
                // Desenhando o botão com estilo de clique
                pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 58);

                // Marca o tempo do clique
                lastOptionButtonClickTime = currentTime;

                // Reproduz som ao clicar
                PlayBuffer(25, 0, 0);

                // Aqui você pode adicionar a funcionalidade que deseja quando o botão for clicado
                // Por exemplo, abrir uma janela de configurações ou opções
                // Por enquanto, apenas fecha o layout como exemplo
                //gInterface.Data[eLayout_MAIN].OnShow = false;
            }
            else
            {
                // Desenhando o botão com estilo de hover
                pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 29);
                this->DrawToolTip(optionButtonX + 5, optionButtonY - 15, "Configurações");
            }
        }
        else
        {
            // Desenhando o botão normal
            pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 0);
        }

        // Desenha o texto "OPTION" no botão
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define a cor do texto como branco brilhante
        gInterface.DrawFormat(eWhite, optionButtonX, optionButtonY + 9, optionButtonWidth, 3, "OPTION");
    }

    // Cria vetores de linhas de texto para cada página

    // Página 1
    std::vector<std::string> textos1;
    textos1.push_back("SEJA BEM VINDO AO MUONLINE");
    textos1.push_back("O continente de MU era glorioso e vasto,");
    textos1.push_back("Quando Kundun surgiu, trazendo o caos mortal.");
    textos1.push_back("Heróis lutaram com força e magia.");
    textos1.push_back("Criaturas sombrias espalharam terror.");

    // Página 2
    std::vector<std::string> textos2;
    textos2.push_back("GUIA DE CLASSES");
    textos2.push_back("SM: Mestre da magia elemental.");
    textos2.push_back("BK: Guerreiro poderoso em combate corpo a corpo.");
    textos2.push_back("Elf: Arqueira ágil com habilidades de suporte.");
    textos2.push_back("MG: Híbrido de força física e poderes mágicos.");
    textos2.push_back("as trevas estavam corruptas");

    // Página 3
    std::vector<std::string> textos3;
    textos3.push_back("MAPAS DE MU ONLINE");
    textos3.push_back("Lorencia: Cidade inicial e principal.");
    textos3.push_back("Noria: Lar dos elfos e seres másticos.");
    textos3.push_back("Davias: Deserto habitado por criaturas perigosas.");
    textos3.push_back("Atlans: Reino subaquático de monstros exóticos.");
    textos3.push_back("as vezes podemos alcançar");

    // Página 4
    std::vector<std::string> textos4;
    textos4.push_back("EVENTOS ESPECIAIS");
    textos4.push_back("Blood Castle: Desafie os guardiões.");
    textos4.push_back("Devil Square: Arena de monstros.");
    textos4.push_back("Chaos Castle: Sobreviva contra monstros.");
    textos4.push_back("Golden Invasion: Lute contra monstros dourados.");
    textos4.push_back("venha vamos correr para alcançar");

    // Página 5
    std::vector<std::string> textos5;

    std::vector<std::vector<std::string>> textosPages;
    textosPages.push_back(textos1);
    textosPages.push_back(textos2);
    textosPages.push_back(textos3);
    textosPages.push_back(textos4);
    textosPages.push_back(textos5);

    // Vetor com os tamanhos (em pontos) padrão para cada linha
    std::vector<int> fontSizes;
    fontSizes.push_back(20);
    fontSizes.push_back(16);
    fontSizes.push_back(16);
    fontSizes.push_back(16);
    fontSizes.push_back(16);

    // Para este exemplo, as linhas da página serão sempre desenhadas com "Segoe UI" (ou outra fonte caso desejado)
    // Se for necessário utilizar fontes diferentes para cada linha, crie um vetor adicional (veja exemplos anteriores)

    // Define o espaçamento vertical entre as linhas (padrão)
    const float linhaAlturaPadrao = 30.0f;
    float linhaAltura = linhaAlturaPadrao;

    // Escolhe o texto da página atual
    std::vector<std::string> textos = textosPages[currentPage];

    // Calcula a posição inicial vertical para centralizar o bloco de texto
    size_t numLines = textos.size();

    // Ajusta a escala do texto continuamente para caber na altura atual do painel
    float textScale = 1.0f;
    if (numLines > 0)
    {
        // Reserva um espaço para botões e margens (topo e base)
        const float margemSuperior = 5.0f;
        const float margemInferior = 35.0f; // área dos botões de navegação
        float alturaDisponivel = MainHeight - (margemSuperior + margemInferior);
        if (alturaDisponivel < 1.0f) alturaDisponivel = 1.0f;

        float alturaPadraoTotal = linhaAlturaPadrao * (float)numLines;
        // Escala limitada a no máximo 1.0 (reduz em telas menores e volta ao padrão quando aumentar)
        textScale = alturaDisponivel / alturaPadraoTotal;
        if (textScale > 1.0f) textScale = 1.0f;
        if (textScale < 0.4f) textScale = 0.4f; // limite inferior para não ficar ilegível

        // Aplica escala ao espaçamento entre linhas
        linhaAltura = linhaAlturaPadrao * textScale;
    }

    float totalTextHeight = linhaAltura * (float)numLines;
    float textStartY = StartY + (MainHeight - totalTextHeight) / 2.0f;
    if (textStartY < StartY + 5.0f) { textStartY = StartY + 5.0f; }

    // Para cada linha, cria e aplica uma fonte personalizada com o tamanho correspondente e desenha o texto centralizado
    for (size_t i = 0; i < textos.size(); i++)
    {
        // Seleciona tamanho base da linha com segurança
        int baseSize = (i < fontSizes.size()) ? fontSizes[i] : 16;

        // Ajusta o tamanho da fonte continuamente conforme a altura do painel
        int drawSize = (int)(baseSize * textScale);
        if (drawSize < 10) drawSize = 10; // tamanho mínimo

        HFONT hCustomFont = CreateFontA(
            -drawSize,   // Tamanho da fonte (em pixels, negativo = altura)
            0,               // Largura: ajuste automático
            0,               // Escapamento
            0,               // Orientação
            FW_BOLD,         // Peso: negrito
            FALSE,           // Não itálico
            FALSE,           // Sem sublinhado
            FALSE,           // Sem tachado
            DEFAULT_CHARSET,
            OUT_TT_PRECIS,
            CLIP_DEFAULT_PRECIS,
            CLEARTYPE_QUALITY,
            DEFAULT_PITCH | FF_DONTCARE,
            "Segoe UI"       // Nome da fonte
        );

        if (hCustomFont)
        {
            pSetFont(pTextThis(), (int)hCustomFont);
            pSetBkColor(pTextThis(), 0, 0, 0, 0); // Define a cor de fundo como transparente
            pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define a cor do texto como branco brilhante
            pDrawText(pTextThis(), StartX, textStartY + i * linhaAltura,
                (LPCTSTR)textos[i].c_str(), MainWidth, 0, (LPINT)3, 0);
            DeleteObject(hCustomFont);
        }
    }

    // Botões de navegação (avançar e voltar) - recalculados após possível drag
    // Recalcula posições usando StartX e StartY atualizados
    float backButtonX_final = StartX + 10.0f;
    float backButtonY_final = StartY + MainHeight - 30.0f;
    float forwardButtonX_final = StartX + MainWidth - 30.0f;
    float forwardButtonY_final = StartY + MainHeight - 30.0f;

    // Botão de voltar (se não estiver na primeira página)
    if (currentPage > 0)
    {
        gInterface.DrawGUI(eLayout_BACK, backButtonX_final, backButtonY_final);

        if (pCheckMouseOver(backButtonX_final, backButtonY_final, buttonWidth, buttonHeight))
        {
            this->DrawToolTip(backButtonX_final + 5, backButtonY_final - 15, "Anterior");

            if (isLeftButtonDown && (currentTime - lastButtonClickTime > clickDelay))
            {
                currentPage--;
                lastButtonClickTime = currentTime;
                PlayBuffer(25, 0, 0);
            }
        }
    }

    // Botão de avançar (se não estiver na última página)
    if (currentPage < maxPages - 1)
    {
        gInterface.DrawGUI(eLayout_FORWARD, forwardButtonX_final, forwardButtonY_final);

        if (pCheckMouseOver(forwardButtonX_final, forwardButtonY_final, buttonWidth, buttonHeight))
        {
            this->DrawToolTip(forwardButtonX_final + 5, forwardButtonY_final - 15, "Próximo");

            if (isLeftButtonDown && (currentTime - lastButtonClickTime > clickDelay))
            {
                currentPage++;
                lastButtonClickTime = currentTime;
                PlayBuffer(25, 0, 0);
            }
        }
    }

    // Desenha o indicador de página com uma fonte fixa para não ser alterado ao passar o mouse sobre as setas
    HFONT hFixedFont = CreateFontA(
        -16,                     // Tamanho fixo da fonte
        0,
        0,
        0,
        FW_BOLD,
        FALSE,
        FALSE,
        FALSE,
        DEFAULT_CHARSET,
        OUT_TT_PRECIS,
        CLIP_DEFAULT_PRECIS,
        CLEARTYPE_QUALITY,
        DEFAULT_PITCH | FF_DONTCARE,
        "Segoe UI"              // Fonte fixa ("Segoe UI")
    );

    if (hFixedFont)
    {
        pSetFont(pTextThis(), (int)hFixedFont);
        char pageText[50];
        sprintf_s(pageText, "Página %d/%d", currentPage + 1, maxPages);
        pSetBkColor(pTextThis(), 0, 0, 0, 0); // Define a cor de fundo como transparente
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define a cor do texto como branco brilhante
        pDrawText(pTextThis(), StartX + MainWidth / 2 - 40, StartY + MainHeight - 30,
            (LPCTSTR)pageText, 80, 0, (LPINT)3, 0);
        DeleteObject(hFixedFont);
    }

    // --- Botão de fechar --- (recalculado após possível drag)
    // Recalcula posição usando StartX e StartY atualizados
    float closeButtonX_final = StartX + MainWidth - 20;
    float closeButtonY_final = StartY - 10;

    gInterface.DrawGUI(eMenu_CLOSE, closeButtonX_final, closeButtonY_final);

    if (pCheckMouseOver(closeButtonX_final, closeButtonY_final, 36, 29))
    {
        this->DrawToolTip(closeButtonX_final + 5, closeButtonY_final + 25, "Close");
    }

    if (pCheckMouseOver(closeButtonX_final, closeButtonY_final, 36, 29) && (GetAsyncKeyState(VK_LBUTTON) & 0x8000))
    {
        // Adiciona o som ao fechar com o botão de fechar
        PlayBuffer(25, 0, 0);

        gInterface.Data[eLayout_MAIN].OnShow = false;
    }
}


Layout.h

#pragma once

class CLayout
{
public:
    CLayout();

    // Atualiza o estado do painel (toggle F4 e drag and drop)
    void UpdateLayoutPanelWindow();

    int DrawToolTip(int X, int Y, LPCSTR Text, ...);

    // Desenha o painel flutuante na posi��o atual
    void DrawLayoutPanelWindow();
};

extern CLayout gLayout;


Interface.cpp

void Interface::Work()
{
gLayout.UpdateLayoutPanelWindow();
gLayout.DrawLayoutPanelWindow();
}
Bon Dia

Dakosmu

#2
Gracias por el aporte aplausos aplausos


Pequeño Ajuste para Presionar F4 y que el cuadro salga Centrado en la pantalla y de normal tamaño
Antes
Regístrate para ver el enlace

cpp

        //Dakosmu
        if (gInterface.Data[eLayout_MAIN].OnShow)
        {
            m_windowWidth = 450.0f;
            m_windowHeight = 400.0f;
            m_windowPosX = (MAX_WIN_WIDTH - m_windowWidth) / 2.0f;
            m_windowPosY = (MAX_WIN_HEIGHT - m_windowHeight) / 2.0f;
        }
        //

.h


    //Dakosmu
    float m_windowWidth = 230.0f;
    float m_windowHeight = 240.0f;
    float m_windowPosX = 0.0f;
    float m_windowPosY = 0.0f;
    //


Interface.h


eLayout_MAIN,


Despues
Regístrate para ver el enlace

COLOCACION DEL CODIGO



Regístrate para ver el enlace
Regístrate para ver el enlace


Bon Dia

Dakosmu

CitarChange Log (Registro de Cambios)
========================================================================
Versión: 1.0
Fecha: 2025-11-13

------------------------------------------------------------------------
VERSION 1.0.0 (2025-11-13) - Core / Base
------------------------------------------------------------------------
- Creación inicial de la estructura de la clase CLayout y sus funciones de control de ventana.

------------------------------------------------------------------------
VERSION 1.0.1 (2025-11-13) - Control F4
------------------------------------------------------------------------
- Implementada la lógica de encendido/apagado (toggle) de la ventana al presionar la tecla F4 (uso de GetAsyncKeyState(VK_F4)).

------------------------------------------------------------------------
VERSION 1.0.2 (2025-11-13) - Centrado
------------------------------------------------------------------------
- IMPLEMENTADA LA FUNCIÓN DE CENTRADO DE VENTANA.
- Al abrir el panel, se calcula y aplica la posición central: m_windowPosX = (MAX_WIN_WIDTH - m_windowWidth) / 2.0f.

------------------------------------------------------------------------
VERSION 1.0.3 (2025-11-13) - Drag/Move
------------------------------------------------------------------------
- Implementada la funcionalidad de arrastrar (Drag and Drop) la ventana usando el botón izquierdo del ratón (VK_LBUTTON).

------------------------------------------------------------------------
VERSION 1.0.4 (2025-11-13) - Redimensionar
------------------------------------------------------------------------
- Implementada la funcionalidad de redimensionamiento (Resize) de la ventana.
- Incluye límites mínimos de tamaño (minW, minH) y límites máximos de pantalla.

------------------------------------------------------------------------
VERSION 1.0.5 (2025-11-13) - Tamaño Fijo al Abrir
------------------------------------------------------------------------
- AÑADIDA LA LÓGICA PARA FORZAR UN TAMAÑO ESPECÍFICO AL ABRIR CON F4.
- El cuadro ahora se inicializa en 450x400 (m_windowWidth = 450.0f; m_windowHeight = 400.0f) justo antes de la rutina de centrado.

------------------------------------------------------------------------
VERSION 1.0.6 (2025-11-13) - Botones
------------------------------------------------------------------------
- Inclusión de lógica para botones de Menú y Opción (visibles solo en la Página 5).

------------------------------------------------------------------------
VERSION 1.0.7 (2025-11-13) - Páginas
------------------------------------------------------------------------
- Implementación de la navegación por páginas (currentPage, maxPages) con botones de Anterior y Próximo.
- Añadido un delay (clickDelay) para evitar clics dobles.

========================================================================
Bon Dia

Dakosmu

#4
💥 MU Online - S6.3 - Layout Resize en Tiempo Real 💥

Layout Resize real time, Con imagen para Regístrate para ver el enlace





---
---

📂 Archivo de Textura (OZT) 📂

Ruta: Custom\Interface\treasure_chest.tga

Regístrate para ver el enlace

---
---

🛠 Modificaciones en el Código Fuente 🛠

Archivo: Interface.cpp

  • Buscar: La función void Interface::Work() y la función void Interface::RenderObjectSystem().
  • Añadir: El código dentro de las funciones según se indica a continuación y la función void Interface::LoadImages().

void Interface::Work()
{
    gLayout.UpdateLayoutPanelWindow();
    gLayout.DrawLayoutPanelWindow();
}


void Interface::RenderObjectSystem()
{
    this->BindObject(eLayout_BACK, 31658, 17, 18, -1, -1);
    this->BindObject(eLayout_FORWARD, 31659, 17, 18, -1, -1);

        // coloque abaixo desses que estão acima
    this->BindObject(eLayout_TREASURE, kLayoutTreasureTextureId, kLayoutTreasureTextureWidth, kLayoutTreasureTextureHeight, -1, -1);
}

void Interface::LoadImages()
{

    pLoadImage("Custom\Interface\treasure_chest.tga", kLayoutTreasureTextureId, 0x2601, 0x2900, 1, 0);
}

---

Archivo: Interface.h

  • Buscar: El enumerador enum ObjectID.
  • Añadir: eLayout_TREASURE debajo de eLayout_FORWARD.

enum ObjectID
{
    eLayout_BACK,
    eLayout_FORWARD,

        // coloque abaixo desses que estão acima
    eLayout_TREASURE,
}

---

Archivo: Layout.cpp

  • Reemplazar/Añadir: Toda la implementación del archivo Layout.cpp con el siguiente código (incluye todas las funciones y definiciones de variables).

#include "stdafx.h"
#include "layout.h"
#include "Interface.h"
#include "Central.h"
#include "Defines.h"
#include "Import.h"
#include "CustomFont.h"
#include "Defines2.h"
#include <vector>
#include <string>
#include <fstream>
#include <windows.h> // Para DWORD, GetTickCount(), VK_F4, etc.
#include <cstdarg> // Para va_start e va_end

// Inicializa o gLayout e as variáveis de drag dentro da classe
CLayout::CLayout()
{
    // Construtor vazio. Caso necessite, adicione inicializações aqui.
}

CLayout gLayout;

void CLayout::UpdateLayoutPanelWindow()
{
    // Variável estática para controlar o estado da tecla F4
    static bool isF4Pressed = false;
    bool currentF4State = (GetAsyncKeyState(VK_F4) & 0x8000) != 0;

    if (currentF4State && !isF4Pressed)
    {
        // Alterna a flag de exibição do painel
        gInterface.Data[eLayout_MAIN].OnShow = !gInterface.Data[eLayout_MAIN].OnShow;

        // Adiciona o som ao abrir ou fechar com F4
        PlayBuffer(25, 0, 0);

        isF4Pressed = true;
    }
    else if (!currentF4State)
    {
        isF4Pressed = false;
    }
}

int CLayout::DrawToolTip(int X, int Y, LPCSTR Text, ...)
{
    // Como estamos tendo problemas com va_start/va_end, vamos usar uma solução mais simples
    // Definir diretamente a cor do texto para branco antes de chamar pDrawToolTip
    pSetTextColor(pTextThis(), 255, 255, 255, 255); // Branco brilhante
   
    // Desenha o tooltip diretamente com o texto fornecido
    int result = pDrawToolTip(X, Y, Text);
   
    return result;
}

// Variáveis globais para controle de páginas
int currentPage = 0;
int maxPages = 5; // Número total de páginas disponíveis
DWORD lastButtonClickTime = 0; // Tempo do último clique nos botões
const DWORD clickDelay = 300; // Delay entre cliques em milissegundos

// Variáveis globais para controle do drag e da posição/tamanho do painel
bool    m_isDragging = false;
POINT  m_dragStartPoint;
float m_windowPosX = (MAX_WIN_WIDTH - 230.0f) / 2;
float m_windowPosY = (MAX_WIN_HEIGHT - 240.0f) / 2;
float m_windowWidth = 230.0f;
float m_windowHeight = 240.0f;

// Variáveis globais para redimensionamento via ícone no topo esquerdo
bool    m_isResizingPanel = false;
POINT  m_resizeStartPoint;
float m_initialPosX = 0.0f;
float m_initialPosY = 0.0f;
float m_initialWidth = 0.0f;
float m_initialHeight = 0.0f;

// Variável para controlar o tempo do último clique no botão de menu
DWORD lastMenuButtonClickTime = 0;
const DWORD menuClickDelay = 300; // Delay entre cliques em milissegundos

// Variável para controlar o tempo do último clique no botão de opções
DWORD lastOptionButtonClickTime = 0;
const DWORD optionClickDelay = 300; // Delay entre cliques em milissegundos

// ID do objeto de interface para o botão de menu
short eLayoutButtonMenu = 12350; // Usando um ID não usado
// ID do objeto de interface para o botão de opções
short eLayoutButtonOption = 12351; // Usando um ID não usado

void CLayout::DrawLayoutPanelWindow()
{
    // Se o painel não estiver para ser exibido, sai da função
    if (!gInterface.Data[eLayout_MAIN].OnShow)
        return;

    // Garante o foco do cursor
    pSetCursorFocus = true;

    // Variáveis para controle de clique e tempo
    bool isLeftButtonDown = (GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0;
    DWORD currentTime = GetTickCount();

    // Dimensões atuais do painel (variáveis para permitir redimensionamento)
    float MainWidth = m_windowWidth;
    float MainHeight = m_windowHeight;

    // Define a posição base para o texto (precisa ser definida antes para calcular posições dos botões)
    float StartX = m_windowPosX;
    float StartY = m_windowPosY;

    // Calcula posições dos elementos interativos antes da lógica de drag
    bool isOverInteractiveElement = false;
   
    // Ícone de redimensionar (lado esquerdo superior) — menor e dentro do layout
    const float resizeIconW = 14.0f;
    const float resizeIconH = 14.0f;
    float resizeIconX = m_windowPosX + 4.0f;
    float resizeIconY = m_windowPosY + 4.0f;
    bool overResizeIcon = pCheckMouseOver(resizeIconX, resizeIconY, resizeIconW, resizeIconH);
   
    // Verifica botão de fechar
    float closeButtonX = m_windowPosX + MainWidth - 20;
    float closeButtonY = m_windowPosY - 10;
    if (pCheckMouseOver(closeButtonX, closeButtonY, 36, 29))
    {
        isOverInteractiveElement = true;
    }
    if (overResizeIcon)
    {
        isOverInteractiveElement = true;
    }
   
    // Verifica botões de navegação
    float buttonWidth = 20.0f;
    float buttonHeight = 20.0f;
    float backButtonX = m_windowPosX + 10.0f;
    float backButtonY = m_windowPosY + MainHeight - 30.0f;
    float forwardButtonX = m_windowPosX + MainWidth - 30.0f;
    float forwardButtonY = m_windowPosY + MainHeight - 30.0f;
   
    if (currentPage > 0 && pCheckMouseOver(backButtonX, backButtonY, buttonWidth, buttonHeight))
    {
        isOverInteractiveElement = true;
    }
    if (currentPage < maxPages - 1 && pCheckMouseOver(forwardButtonX, forwardButtonY, buttonWidth, buttonHeight))
    {
        isOverInteractiveElement = true;
    }
   
    // Verifica botões de menu e opções (apenas na página 5)
    if (currentPage == 4)
    {
        float menuButtonWidth = 107.1f;
        float menuButtonHeight = 29.0f;
        float menuButtonX = m_windowPosX + (MainWidth / 2) - (menuButtonWidth / 2);
        float menuButtonY = m_windowPosY + 5.0f;
       
        float optionButtonWidth = 107.1f;
        float optionButtonHeight = 29.0f;
        float optionButtonX = m_windowPosX + (MainWidth / 2) - (optionButtonWidth / 2);
        float optionButtonY = menuButtonY + menuButtonHeight + 5.0f;
       
        if (pCheckMouseOver(menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight) ||
            pCheckMouseOver(optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight))
        {
            isOverInteractiveElement = true;
        }
    }

    // Lógica de redimensionamento (prioritária sobre drag)
    if (m_isResizingPanel)
    {
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
        {
            float deltaX = pCursorX - m_resizeStartPoint.x;
            float deltaY = pCursorY - m_resizeStartPoint.y;

            // Ancorado no canto inferior-direito, arrastando o topo-esquerdo
            float newPosX = m_initialPosX + deltaX;
            float newPosY = m_initialPosY + deltaY;
            float newWidth = m_initialWidth - deltaX;
            float newHeight = m_initialHeight - deltaY;

            // Mínimos
            const float minW = 180.0f;
            const float minH = 140.0f;

            if (newWidth < minW)
            {
                // Corrige posição para manter a borda direita estável
                newPosX -= (minW - newWidth);
                newWidth = minW;
            }
            if (newHeight < minH)
            {
                newPosY -= (minH - newHeight);
                newHeight = minH;
            }

            // Limites da tela (painel deve ficar visível)
            if (newPosX < 0.0f)
            {
                // Ao sair pela esquerda, ajusta largura e posição
                float excess = -newPosX;
                newPosX = 0.0f;
                newWidth += excess;
            }
            if (newPosY < 0.0f)
            {
                float excess = -newPosY;
                newPosY = 0.0f;
                newHeight += excess;
            }
            if (newPosX + newWidth > MAX_WIN_WIDTH)
            {
                newWidth = MAX_WIN_WIDTH - newPosX;
            }
            if (newPosY + newHeight > MAX_WIN_HEIGHT)
            {
                newHeight = MAX_WIN_HEIGHT - newPosY;
            }

            // Aplica
            m_windowPosX = newPosX;
            m_windowPosY = newPosY;
            m_windowWidth = newWidth;
            m_windowHeight = newHeight;

            // Atualiza cópias locais usadas no desenho
            MainWidth = m_windowWidth;
            MainHeight = m_windowHeight;
        }
        else
        {
            m_isResizingPanel = false;
        }
    }
    else if (overResizeIcon && (GetAsyncKeyState(VK_LBUTTON) & 0x8000))
    {
        // Inicia redimensionamento
        m_isResizingPanel = true;
        m_resizeStartPoint.x = pCursorX;
        m_resizeStartPoint.y = pCursorY;
        m_initialPosX = m_windowPosX;
        m_initialPosY = m_windowPosY;
        m_initialWidth = m_windowWidth;
        m_initialHeight = m_windowHeight;
        PlayBuffer(25, 0, 0);
    }

    // Lógica para drag and drop
    // Se já estiver arrastando, continua arrastando mesmo sobre elementos interativos
    if (!m_isResizingPanel && m_isDragging)
    {
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
        {
            float deltaX = pCursorX - m_dragStartPoint.x;
            float deltaY = pCursorY - m_dragStartPoint.y;

            m_windowPosX += deltaX;
            m_windowPosY += deltaY;

            if (m_windowPosX < 0)
                m_windowPosX = 0;
            else if (m_windowPosX > MAX_WIN_WIDTH - MainWidth)
                m_windowPosX = MAX_WIN_WIDTH - MainWidth;

            if (m_windowPosY < 0)
                m_windowPosY = 0;
            else if (m_windowPosY > MAX_WIN_HEIGHT - MainHeight)
                m_windowPosY = MAX_WIN_HEIGHT - MainHeight;

            m_dragStartPoint.x = pCursorX;
            m_dragStartPoint.y = pCursorY;
        }
        else
        {
            m_isDragging = false;
        }
    }
    // Se não estiver arrastando, verifica se pode iniciar o drag
    else if (!m_isResizingPanel && pCheckMouseOver(m_windowPosX, m_windowPosY, MainWidth, MainHeight))
    {
        // Só inicia o drag se não estiver sobre um elemento interativo
        if (GetAsyncKeyState(VK_LBUTTON) & 0x8000 && !isOverInteractiveElement)
        {
            m_isDragging = true;
            m_dragStartPoint.x = pCursorX;
            m_dragStartPoint.y = pCursorY;
        }
    }

    // Desenha o painel flutuante na posição atual
    gCentral.PrintDropBox(m_windowPosX, m_windowPosY, MainWidth, MainHeight, 0, 0);
   
    // Desenha o ícone de redimensionar (esquerda superior)
    if (overResizeIcon)
    {
        pDrawButton(0x7A5E, resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0, (GetAsyncKeyState(VK_LBUTTON) & 0x8000) ? 58 : 29);
        // Camada semitransparente para dar aparência "meio transparente"
        gInterface.DrawBarForm(resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0.0f, 0.0f, 0.0f, 0.45f);
        this->DrawToolTip(resizeIconX + 5, resizeIconY + 25, "Redimensionar");
    }
    else
    {
        pDrawButton(0x7A5E, resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0, 0);
        // Camada semitransparente para dar aparência "meio transparente"
        gInterface.DrawBarForm(resizeIconX, resizeIconY, resizeIconW, resizeIconH, 0.0f, 0.0f, 0.0f, 0.45f);
    }
   
    // Atualiza StartX e StartY após possível movimento do drag
    StartX = m_windowPosX;
    StartY = m_windowPosY;

    // --- Botão de menu ---
    // Mostrar o botão apenas na página 5 (índice 4)
    if (currentPage == 4)
    {
        // Definindo as dimensões e posição do botão menu (já calculadas acima)
        float menuButtonWidth = 107.1f; // Mesma largura do botão Menu Option
        float menuButtonHeight = 29.0f; // Mesma altura do botão Menu Option
        float menuButtonX = StartX + (MainWidth / 2) - (menuButtonWidth / 2);
        float menuButtonY = StartY + 5.0f; // Posicionado mais acima

        // Vinculando o objeto de botão de menu (apenas uma vez)
        static bool buttonBound = false;
        if (!buttonBound) {
            gInterface.BindObject(eLayoutButtonMenu, 0x7A5E, menuButtonWidth, menuButtonHeight, -1, -1);
            gInterface.BindObject(eLayoutButtonOption, 0x7A5E, menuButtonWidth, menuButtonHeight, -1, -1);
            buttonBound = true;
        }

        // Desenhando o botão do menu
        bool isHovered = pCheckMouseOver(menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight);

        // Verificando se está sobre o botão
        if (isHovered)
        {
            if (isLeftButtonDown && (currentTime - lastMenuButtonClickTime > menuClickDelay))
            {
                // Desenhando o botão com estilo de clique
                pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 58);

                // Marca o tempo do clique
                lastMenuButtonClickTime = currentTime;

                // Reproduz som ao clicar
                PlayBuffer(25, 0, 0);

                // Fecha o painel de layout
                //gInterface.Data[eLayout_MAIN].OnShow = false;

                // aqui abre menu option
                //if (!gInterface.CheckMenuWindow())
                //{
                //    gInterface.CloseCustomWindow();
                //    gInterface.OpenMenuWindow();
                //}
            }
            else
            {
                // Desenhando o botão com estilo de hover
                pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 29);
                this->DrawToolTip(menuButtonX + 5, menuButtonY - 15, "Abrir Menu");
            }
        }
        else
        {
            // Desenhando o botão normal
            pDrawButton(0x7A5E, menuButtonX, menuButtonY, menuButtonWidth, menuButtonHeight, 0, 0);
        }

        // Desenha o texto "MENU" no botão
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define a cor do texto como branco brilhante
        gInterface.DrawFormat(eWhite, menuButtonX, menuButtonY + 9, menuButtonWidth, 3, "MENU");

        // ----- Botão Option -----
        // Posicionando o botão Option abaixo do botão Menu (já calculadas acima)
        float optionButtonWidth = 107.1f;
        float optionButtonHeight = 29.0f;
        float optionButtonX = StartX + (MainWidth / 2) - (optionButtonWidth / 2);
        float optionButtonY = menuButtonY + menuButtonHeight + 5.0f; // 5 pixels abaixo do botão menu

        // Desenhando o botão de opções
        bool isOptionHovered = pCheckMouseOver(optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight);

        // Verificando se está sobre o botão
        if (isOptionHovered)
        {
            if (isLeftButtonDown && (currentTime - lastOptionButtonClickTime > optionClickDelay))
            {
                // Desenhando o botão com estilo de clique
                pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 58);

                // Marca o tempo do clique
                lastOptionButtonClickTime = currentTime;

                // Reproduz som ao clicar
                PlayBuffer(25, 0, 0);

                // Aqui você pode adicionar a funcionalidade que deseja quando o botão for clicado
                // Por exemplo, abrir uma janela de configurações ou opções
                // Por enquanto, apenas fecha o layout como exemplo
                //gInterface.Data[eLayout_MAIN].OnShow = false;
            }
            else
            {
                // Desenhando o botão com estilo de hover
                pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 29);
                this->DrawToolTip(optionButtonX + 5, optionButtonY - 15, "Configurações");
            }
        }
        else
        {
            // Desenhando o botão normal
            pDrawButton(0x7A5E, optionButtonX, optionButtonY, optionButtonWidth, optionButtonHeight, 0, 0);
        }

        // Desenha o texto "OPTION" no botão
        pSetTextColor(pTextThis(), 255, 255, 255, 255); // Define a cor do texto como branco brilhante
        gInterface.DrawFormat(eWhite, optionButtonX, optionButtonY + 9, optionButtonWidth, 3, "OPTION");
    }

    // Cria vetores de linhas de texto para cada página

    // Página 1
    std::vector<std::string> textos1;
    textos1.push_back("SEJA BEM VINDO AO MUONLINE");
    textos1.push_back("O continente de MU era glorioso e vasto,");
    textos1.push_back("Quando Kundun surgiu, trazendo o caos mortal.");
    textos1.push_back("Heróis lutaram com força e magia.");
    textos1.push_back("Criaturas sombrias espalharam terror.");

    // Página 2
    std::vector<std::string> textos2;
    textos2.push_back("GUIA DE CLASSES");
    textos2.push_back("SM: Mestre da magia elemental.");
    textos2.push_back("BK: Guerreiro poderoso em combate corpo a corpo.");
    textos2.push_back("Elf: Arqueira ágil com habilidades de suporte.");
    textos2.push_back("MG: Híbrido de força física e poderes mágicos.");
    textos2.push_back("as trevas estavam corruptas");

    // Página 3
    std::vector<std::string> textos3;
    textos3.push_back("MAPAS DE MU ONLINE");
    textos3.push_back("Lorencia: Cidade inicial e principal.");
    textos3.push_back("Noria: Lar dos elfos e seres másticos.");
    textos3.push_back("Davias: Deserto habitado por criaturas perigosas.");
    textos3.push_back("Atlans: Reino subaquático de monstros exóticos.");
    textos3.push_back("as vezes podemos alcançar");

    // Página 4
    std::vector<std::string> textos4;
    textos4.push_back("EVENTOS ESPECIAIS");
    textos4.push_back("Blood Castle: Desafie os guardiões.");
    textos4.push_back("Devil Square: Arena de monstros.");
    textos4.push_back("Chaos Castle: Sobreviva contra monstros.");
    textos4.push_back("Golden Invasion: Lute contra monstros dourados.");
    textos4.push_back("venha vamos correr para alcançar");

    // Página 5
    std::vector<std::string> textos5;

    std::vector<std::vector<std::string>> textosPages;
    textosPages.push_back(textos1);
    textosPages.push_back(textos2);
}


Regístrate para ver el enlace
Bon Dia

🡱 🡳
Real Time Web Analytics