From 60d8ea389fb2cc2b4c61508386f169c2fe2e8263 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 5 Jan 2025 04:29:30 -0500 Subject: [PATCH 1/2] Support for printer configuration --- src/device/lpt.c | 68 ++++++++++++++++------- src/include/86box/lpt.h | 101 ++++++++++++++++++++--------------- src/include/86box/prt_devs.h | 4 ++ src/network/net_plip.c | 1 - src/printer/prt_escp.c | 45 +++++++++++++++- src/printer/prt_ps.c | 1 + src/printer/prt_text.c | 44 ++++++++++++++- src/qt/qt_settingsports.cpp | 90 ++++++++++++++++++++++++++++++- src/qt/qt_settingsports.hpp | 9 ++++ src/qt/qt_settingsports.ui | 64 +++++++++++++++++++--- 10 files changed, 352 insertions(+), 75 deletions(-) diff --git a/src/device/lpt.c b/src/device/lpt.c index 71f96303e..c54345856 100644 --- a/src/device/lpt.c +++ b/src/device/lpt.c @@ -9,6 +9,7 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/device.h> #include <86box/io.h> #include <86box/fifo.h> #include <86box/timer.h> @@ -42,23 +43,22 @@ const lpt_device_t lpt_none_device = { }; static const struct { - const char *internal_name; const lpt_device_t *device; } lpt_devices[] = { // clang-format off - {"none", &lpt_none_device }, - {"dss", &dss_device }, - {"lpt_dac", &lpt_dac_device }, - {"lpt_dac_stereo", &lpt_dac_stereo_device }, - {"text_prt", &lpt_prt_text_device }, - {"dot_matrix", &lpt_prt_escp_device }, - {"postscript", &lpt_prt_ps_device }, + { &lpt_none_device }, + { &dss_device }, + { &lpt_dac_device }, + { &lpt_dac_stereo_device }, + { &lpt_prt_text_device }, + { &lpt_prt_escp_device }, + { &lpt_prt_ps_device }, #ifdef USE_PCL - {"pcl", &lpt_prt_pcl_device }, + { &lpt_prt_pcl_device }, #endif - {"plip", &lpt_plip_device }, - {"dongle_savquest", &lpt_hasp_savquest_device }, - {"", NULL } + { &lpt_plip_device }, + { &lpt_hasp_savquest_device }, + { NULL } // clang-format on }; @@ -80,31 +80,59 @@ lpt_log(const char *fmt, ...) # define lpt_log(fmt, ...) #endif +const device_t * +lpt_device_getdevice(const int id) +{ + return (device_t *) lpt_devices[id].device->cfgdevice; +} + +int +lpt_device_has_config(const int id) +{ + int c = 0; + const device_t *dev = (device_t *) lpt_devices[id].device->cfgdevice; + const device_config_t *config; + if (dev == NULL) + return 0; + + if (dev->config == NULL) + return 0; + + config = dev->config; + + while (config->type != CONFIG_END) { + c++; + config++; + } + + return (c > 0) ? 1 : 0; +} + const char * lpt_device_get_name(const int id) { - if (strlen(lpt_devices[id].internal_name) == 0) - return NULL; if (lpt_devices[id].device == NULL) - return "None"; + return NULL; + return lpt_devices[id].device->name; } const char * lpt_device_get_internal_name(const int id) { - if (strlen(lpt_devices[id].internal_name) == 0) + if (lpt_devices[id].device == NULL) return NULL; - return lpt_devices[id].internal_name; + + return lpt_devices[id].device->internal_name; } int -lpt_device_get_from_internal_name(const char *s) +lpt_device_get_from_internal_name(const char *str) { int c = 0; - while (strlen(lpt_devices[c].internal_name) != 0) { - if (strcmp(lpt_devices[c].internal_name, s) == 0) + while (lpt_devices[c].device != NULL) { + if (!strcmp(lpt_devices[c].device->internal_name, str)) return c; c++; } diff --git a/src/include/86box/lpt.h b/src/include/86box/lpt.h index 609e792b7..4e3adf406 100644 --- a/src/include/86box/lpt.h +++ b/src/include/86box/lpt.h @@ -17,25 +17,31 @@ #define LPT6_IRQ 5 #endif -typedef struct lpt_device_t { - const char * name; - const char * internal_name; +typedef struct lpt_device_s { + const char *name; + const char *internal_name; - void * (*init)(void *lpt); - void (*close)(void *priv); - void (*write_data)(uint8_t val, void *priv); - void (*write_ctrl)(uint8_t val, void *priv); - void (*autofeed)(uint8_t val,void *priv); - void (*strobe)(uint8_t old, uint8_t val,void *priv); - uint8_t (*read_status)(void *priv); - uint8_t (*read_ctrl)(void *priv); - void (*epp_write_data)(uint8_t is_addr, uint8_t val, void *priv); - void (*epp_request_read)(uint8_t is_addr, void *priv); + void *(*init)(void *lpt); + void (*close)(void *priv); + void (*write_data)(uint8_t val, void *priv); + void (*write_ctrl)(uint8_t val, void *priv); + void (*autofeed)(uint8_t val,void *priv); + void (*strobe)(uint8_t old, uint8_t val,void *priv); + uint8_t (*read_status)(void *priv); + uint8_t (*read_ctrl)(void *priv); + void (*epp_write_data)(uint8_t is_addr, uint8_t val, void *priv); + void (*epp_request_read)(uint8_t is_addr, void *priv); - void * priv; + void *priv; struct lpt_t *lpt; +//#ifdef EMU_DEVICE_H +// struct device_t *cfgdevice; +//#else + void *cfgdevice; +//#endif } lpt_device_t; +#ifdef _TIMER_H_ typedef struct lpt_t { uint8_t enabled; uint8_t irq; @@ -70,6 +76,7 @@ typedef struct lpt_t { pc_timer_t fifo_out_timer; } lpt_t; +#endif /* _TIMER_H_ */ typedef struct lpt_port_s { uint8_t enabled; @@ -85,49 +92,55 @@ typedef enum { LPT_STATE_WRITE_FIFO } lpt_state_t; -extern void lpt_write(uint16_t port, uint8_t val, void *priv); +extern void lpt_write(uint16_t port, uint8_t val, void *priv); -extern void lpt_write_to_fifo(void *priv, uint8_t val); +extern void lpt_write_to_fifo(void *priv, uint8_t val); -extern uint8_t lpt_read(uint16_t port, void *priv); +extern uint8_t lpt_read(uint16_t port, void *priv); -extern uint8_t lpt_read_port(lpt_t *dev, uint16_t reg); +extern uint8_t lpt_read_port(lpt_t *dev, uint16_t reg); -extern uint8_t lpt_read_status(lpt_t *dev); -extern void lpt_irq(void *priv, int raise); +extern uint8_t lpt_read_status(lpt_t *dev); +extern void lpt_irq(void *priv, int raise); -extern int lpt_device_get_from_internal_name(const char *s); +extern int lpt_device_get_from_internal_name(const char *str); -extern const char * lpt_device_get_name(int id); -extern const char * lpt_device_get_internal_name(int id); +extern const char *lpt_device_get_name(int id); +extern const char *lpt_device_get_internal_name(int id); -extern const lpt_device_t lpt_dac_device; -extern const lpt_device_t lpt_dac_stereo_device; +#ifdef EMU_DEVICE_H +extern const device_t *lpt_device_getdevice(const int id); +#endif -extern const lpt_device_t dss_device; +extern int lpt_device_has_config(const int id); -extern const lpt_device_t lpt_hasp_savquest_device; +extern const lpt_device_t lpt_dac_device; +extern const lpt_device_t lpt_dac_stereo_device; -extern void lpt_set_ext(lpt_t *dev, uint8_t ext); -extern void lpt_set_ecp(lpt_t *dev, uint8_t ecp); -extern void lpt_set_epp(lpt_t *dev, uint8_t epp); -extern void lpt_set_lv2(lpt_t *dev, uint8_t lv2); -extern void lpt_set_fifo_threshold(lpt_t *dev, int threshold); -extern void lpt_set_cnfga_readout(lpt_t *dev, const uint8_t cnfga_readout); -extern void lpt_port_setup(lpt_t *dev, uint16_t port); -extern void lpt_port_irq(lpt_t *dev, uint8_t irq); -extern void lpt_port_dma(lpt_t *dev, uint8_t dma); -extern void lpt_port_remove(lpt_t *dev); -extern void lpt1_remove_ams(lpt_t *dev); +extern const lpt_device_t dss_device; -extern void lpt_devices_init(void); -extern void lpt_devices_close(void); +extern const lpt_device_t lpt_hasp_savquest_device; -extern void lpt_set_next_inst(int ni); -extern void lpt_set_3bc_used(int is_3bc_used); +extern void lpt_set_ext(lpt_t *dev, uint8_t ext); +extern void lpt_set_ecp(lpt_t *dev, uint8_t ecp); +extern void lpt_set_epp(lpt_t *dev, uint8_t epp); +extern void lpt_set_lv2(lpt_t *dev, uint8_t lv2); +extern void lpt_set_fifo_threshold(lpt_t *dev, int threshold); +extern void lpt_set_cnfga_readout(lpt_t *dev, const uint8_t cnfga_readout); +extern void lpt_port_setup(lpt_t *dev, uint16_t port); +extern void lpt_port_irq(lpt_t *dev, uint8_t irq); +extern void lpt_port_dma(lpt_t *dev, uint8_t dma); +extern void lpt_port_remove(lpt_t *dev); +extern void lpt1_remove_ams(lpt_t *dev); -extern void lpt_standalone_init(void); +extern void lpt_devices_init(void); +extern void lpt_devices_close(void); -extern const device_t lpt_port_device; +extern void lpt_set_next_inst(int ni); +extern void lpt_set_3bc_used(int is_3bc_used); + +extern void lpt_standalone_init(void); + +extern const device_t lpt_port_device; #endif /*EMU_LPT_H*/ diff --git a/src/include/86box/prt_devs.h b/src/include/86box/prt_devs.h index 1379c8fa8..d136d9d93 100644 --- a/src/include/86box/prt_devs.h +++ b/src/include/86box/prt_devs.h @@ -2,10 +2,14 @@ #define EMU_PRT_DEVS_H extern const lpt_device_t lpt_prt_text_device; +extern const device_t prt_text_device; extern const lpt_device_t lpt_prt_escp_device; +extern const device_t prt_escp_device; extern const lpt_device_t lpt_prt_ps_device; +extern const device_t prt_ps_device; #ifdef USE_PCL extern const lpt_device_t lpt_prt_pcl_device; +extern const device_t prt_pcl_device; #endif #endif /*EMU_PRT_DEVS_H*/ diff --git a/src/network/net_plip.c b/src/network/net_plip.c index 41a2a4532..c45ad5527 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -31,7 +31,6 @@ #include <86box/lpt.h> #include <86box/timer.h> #include <86box/pit.h> -#include <86box/device.h> #include <86box/thread.h> #include <86box/network.h> #include <86box/plat_unused.h> diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 5e1c52344..6340c26af 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -57,6 +57,7 @@ #include FT_FREETYPE_H #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/device.h> #include "cpu.h" #include <86box/machine.h> #include <86box/timer.h> @@ -2096,6 +2097,47 @@ escp_close(void *priv) free(dev); } +// clang-format off +#if 0 +static const device_config_t lpt_prt_escp_config[] = { + { + .name = "paper_size", + .description = "Paper Size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Letter", .value = 0 }, + { .description = "A4", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +#endif +// clang-format on + +const device_t prt_escp_device = { + .name = "Generic ESC/P Dot-Matrix Printer", + .internal_name = "dot_matrix", + .flags = DEVICE_LPT, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, +#if 0 + .config = lpt_prt_escp_config +#else + .config = NULL +#endif +}; + const lpt_device_t lpt_prt_escp_device = { .name = "Generic ESC/P Dot-Matrix Printer", .internal_name = "dot_matrix", @@ -2110,5 +2152,6 @@ const lpt_device_t lpt_prt_escp_device = { .epp_write_data = NULL, .epp_request_read = NULL, .priv = NULL, - .lpt = NULL + .lpt = NULL, + .cfgdevice = &prt_escp_device }; diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index fde6ab908..c7183ec3f 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -26,6 +26,7 @@ #include #include #include <86box/86box.h> +#include <86box/device.h> #include <86box/timer.h> #include <86box/device.h> #include <86box/lpt.h> diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index ffd6e809c..ffd5e8248 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -513,6 +513,47 @@ prnt_close(void *priv) free(dev); } +// clang-format off +#if 0 +static const device_config_t lpt_prt_text_config[] = { + { + .name = "paper_size", + .description = "Paper Size", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Letter", .value = 0 }, + { .description = "A4", .value = 1 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +#endif +// clang-format on + +const device_t prt_text_device = { + .name = "Generic Text Printer", + .internal_name = "text_prt", + .flags = DEVICE_LPT, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, +#if 0 + .config = lpt_prt_text_config +#else + .config = NULL +#endif +}; + const lpt_device_t lpt_prt_text_device = { .name = "Generic Text Printer", .internal_name = "text_prt", @@ -527,5 +568,6 @@ const lpt_device_t lpt_prt_text_device = { .epp_write_data = NULL, .epp_request_read = NULL, .priv = NULL, - .lpt = NULL + .lpt = NULL, + .cfgdevice = &prt_text_device }; diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index ddebd28e8..5abe0a805 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -111,11 +111,17 @@ SettingsPorts::onCurrentMachineChanged(int machineId) cbox[i]->setCurrentIndex(-1); cbox[i]->setCurrentIndex(selectedRows[i]); - auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); + auto *checkBox = findChild(QString("checkBoxParallel%1").arg(i + 1)); + auto *buttonCfg = findChild(QString("pushButtonConfigureLpt%1").arg(i + 1)); if (checkBox != NULL) checkBox->setChecked(lpt_ports[i].enabled > 0); - if (cbox[i] != NULL) + if (cbox[i] != NULL) { cbox[i]->setEnabled(lpt_ports[i].enabled > 0); + if (buttonCfg != NULL) { + int lptDevice = cbox[i]->currentData().toInt(); + buttonCfg->setEnabled(lpt_device_has_config(lptDevice) && (lpt_ports[i].enabled > 0)); + } + } } for (int i = 0; i < (SERIAL_MAX - 1); i++) { @@ -132,6 +138,86 @@ SettingsPorts::onCurrentMachineChanged(int machineId) } } +void +SettingsPorts::on_comboBoxLpt1_currentIndexChanged(int index) +{ + if (index < 0) + return; + + int lptDevice = ui->comboBoxLpt1->currentData().toInt(); + + ui->pushButtonConfigureLpt1->setEnabled(lpt_device_has_config(lptDevice)); +} + +void +SettingsPorts::on_pushButtonConfigureLpt1_clicked() +{ + int lptDevice = ui->comboBoxLpt1->currentData().toInt(); + auto *device = lpt_device_getdevice(lptDevice); + + DeviceConfig::ConfigureDevice(device, 1); +} + +void +SettingsPorts::on_comboBoxLpt2_currentIndexChanged(int index) +{ + if (index < 0) + return; + + int lptDevice = ui->comboBoxLpt2->currentData().toInt(); + + ui->pushButtonConfigureLpt2->setEnabled(lpt_device_has_config(lptDevice)); +} + +void +SettingsPorts::on_pushButtonConfigureLpt2_clicked() +{ + int lptDevice = ui->comboBoxLpt2->currentData().toInt(); + auto *device = lpt_device_getdevice(lptDevice); + + DeviceConfig::ConfigureDevice(device, 1); +} + +void +SettingsPorts::on_comboBoxLpt3_currentIndexChanged(int index) +{ + if (index < 0) + return; + + int lptDevice = ui->comboBoxLpt3->currentData().toInt(); + + ui->pushButtonConfigureLpt3->setEnabled(lpt_device_has_config(lptDevice)); +} + +void +SettingsPorts::on_pushButtonConfigureLpt3_clicked() +{ + int lptDevice = ui->comboBoxLpt3->currentData().toInt(); + auto *device = lpt_device_getdevice(lptDevice); + + DeviceConfig::ConfigureDevice(device, 1); +} + +void +SettingsPorts::on_comboBoxLpt4_currentIndexChanged(int index) +{ + if (index < 0) + return; + + int lptDevice = ui->comboBoxLpt4->currentData().toInt(); + + ui->pushButtonConfigureLpt4->setEnabled(lpt_device_has_config(lptDevice)); +} + +void +SettingsPorts::on_pushButtonConfigureLpt4_clicked() +{ + int lptDevice = ui->comboBoxLpt4->currentData().toInt(); + auto *device = lpt_device_getdevice(lptDevice); + + DeviceConfig::ConfigureDevice(device, 1); +} + void SettingsPorts::on_checkBoxParallel1_stateChanged(int state) { diff --git a/src/qt/qt_settingsports.hpp b/src/qt/qt_settingsports.hpp index 8be1f0491..f6024b094 100644 --- a/src/qt/qt_settingsports.hpp +++ b/src/qt/qt_settingsports.hpp @@ -20,6 +20,15 @@ public slots: void onCurrentMachineChanged(int machineId); private slots: + void on_comboBoxLpt1_currentIndexChanged(int index); + void on_pushButtonConfigureLpt1_clicked(); + void on_comboBoxLpt2_currentIndexChanged(int index); + void on_pushButtonConfigureLpt2_clicked(); + void on_comboBoxLpt3_currentIndexChanged(int index); + void on_pushButtonConfigureLpt3_clicked(); + void on_comboBoxLpt4_currentIndexChanged(int index); + void on_pushButtonConfigureLpt4_clicked(); + void on_checkBoxParallel1_stateChanged(int state); void on_checkBoxParallel2_stateChanged(int state); void on_checkBoxParallel3_stateChanged(int state); diff --git a/src/qt/qt_settingsports.ui b/src/qt/qt_settingsports.ui index 92420f2df..0ac4cb92c 100644 --- a/src/qt/qt_settingsports.ui +++ b/src/qt/qt_settingsports.ui @@ -13,7 +13,7 @@ Form - + 0 @@ -27,7 +27,7 @@ 0 - + @@ -35,13 +35,26 @@ - + + + + 0 + 0 + + 30 + + + + Configure + + + @@ -49,13 +62,26 @@ - + + + + 0 + 0 + + 30 + + + + Configure + + + @@ -63,13 +89,26 @@ - + + + + 0 + 0 + + 30 + + + + Configure + + + @@ -77,13 +116,26 @@ - + + + + 0 + 0 + + 30 + + + + Configure + + + From b2067d79465fecfbc27ef28781ef343065b9ae81 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 3 Aug 2025 22:06:33 -0400 Subject: [PATCH 2/2] Paper Sizes --- src/include/86box/prt_papersizes.h | 50 ++++++++++++++++++++++++++++++ src/printer/prt_escp.c | 7 +++-- src/printer/prt_text.c | 5 +-- 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 src/include/86box/prt_papersizes.h diff --git a/src/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h new file mode 100644 index 000000000..c45c74568 --- /dev/null +++ b/src/include/86box/prt_papersizes.h @@ -0,0 +1,50 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Define the various paper sizes for printers. + * + * Authors: Jasmine Iwanek, + * + * Copyright 2025 Jasmine Iwanek + */ +#ifndef EMU_PRT_PAPERSIZES_H +#define EMU_PRT_PAPERSIZES_H + +/* Standard U.S. Letter */ +#define LETTER_PAGE_WIDTH 8.5 +#define LETTER_PAGE_HEIGHT 11.0 + +/* Standard U.S. Legal */ +#define LEGAL_PAGE_WIDTH 8.5 +#define LEGAL_PAGE_HEIGHT 14.0 + +/* Standard U.S. Ledger */ +#define LEDGER_PAGE_WIDTH 11.0 +#define LEDGER_PAGE_HEIGHT 17.0 + +/* Standard A0 */ +#define A0_PAGE_WIDTH 33.125 +#define A0_PAGE_HEIGHT 46.75 + +/* Standard A1 */ +#define A1_PAGE_WIDTH 23.375 +#define A1_PAGE_HEIGHT 33.125 + +/* Standard A2 */ +#define A2_PAGE_WIDTH 16.5 +#define A2_PAGE_HEIGHT 23.375 + +/* Standard A3 */ +#define A3_PAGE_WIDTH 11.75 +#define A3_PAGE_HEIGHT 16.5 + +/* Standard A4 */ +#define A4_PAGE_WIDTH 8.25 +#define A4_PAGE_HEIGHT 11.75 + +#endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 6340c26af..a210dcaa1 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -72,15 +72,18 @@ #include <86box/png_struct.h> #include <86box/printer.h> #include <86box/prt_devs.h> +#include <86box/prt_papersizes.h> /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ -#define PAGE_HEIGHT 11.0 +#define PAGE_WIDTH LETTER_PAGE_WIDTH +#define PAGE_HEIGHT LETTER_PAGE_HEIGHT +#if 0 #define PAGE_LMARGIN 0.0 #define PAGE_RMARGIN PAGE_WIDTH #define PAGE_TMARGIN 0.0 #define PAGE_BMARGIN PAGE_HEIGHT +#endif #define PAGE_DPI 360 #define PAGE_CPI 10.0 /* standard 10 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index ffd5e8248..24055073b 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -64,12 +64,13 @@ #include <86box/printer.h> #include <86box/prt_devs.h> #include "cpu.h" +#include <86box/prt_papersizes.h> #define FULL_PAGE 1 /* set if no top/bot margins */ /* Default page values (for now.) */ -#define PAGE_WIDTH 8.5 /* standard U.S. Letter */ -#define PAGE_HEIGHT 11 +#define PAGE_WIDTH LETTER_PAGE_WIDTH +#define PAGE_HEIGHT LETTER_PAGE_HEIGHT #define PAGE_LMARGIN 0.25 /* 0.25" left and right */ #define PAGE_RMARGIN 0.25 #if FULL_PAGE