2018-02-08 23:40:26 +00:00
// Hyperbolic Rogue -- dialogs
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
2019-08-10 11:43:24 +00:00
/** \file dialogs.cpp
* \ brief Implementation of various generic dialogs and elements of dialog windows
*/
2017-03-23 10:53:57 +00:00
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2018-06-10 23:58:31 +00:00
namespace hr {
2019-08-10 00:16:48 +00:00
EX const char * COLORBAR = " ### " ;
2017-10-29 11:46:57 +00:00
2019-08-09 19:00:52 +00:00
EX namespace dialog {
# if HDR
2019-08-10 08:57:14 +00:00
# define IFM(x) (mousing?"":x)
2023-08-23 17:44:37 +00:00
static constexpr int DONT_SHOW = 16 ;
2019-08-09 19:00:52 +00:00
2023-08-08 15:20:39 +00:00
enum tDialogItem { diTitle , diItem , diBreak , diHelp , diInfo , diIntSlider , diSlider , diBigItem , diKeyboard , diCustom , diColorItem , diListStart , diListEnd , diMatrixItem } ;
2019-08-09 19:00:52 +00:00
struct item {
tDialogItem type ;
string body ;
string value ;
2024-06-17 23:04:48 +00:00
key_type key ;
2019-08-09 19:00:52 +00:00
color_t color , colorv , colork , colors , colorc ;
int scale ;
double param ;
int p1 , p2 , p3 ;
int position ;
2023-08-08 15:20:39 +00:00
void * ptr ;
2022-04-16 11:58:26 +00:00
reaction_t customfun ;
2022-12-04 14:24:42 +00:00
item ( tDialogItem t = diBreak ) ;
2019-08-09 19:00:52 +00:00
} ;
struct scaler {
ld ( * direct ) ( ld ) ;
ld ( * inverse ) ( ld ) ;
bool positive ;
} ;
2020-02-23 01:51:27 +00:00
static inline ld identity_f ( ld x ) { return x ; }
2019-08-09 19:00:52 +00:00
const static scaler identity = { identity_f , identity_f , false } ;
const static scaler logarithmic = { log , exp , true } ;
const static scaler asinhic = { asinh , sinh , false } ;
const static scaler asinhic100 = { [ ] ( ld x ) { return asinh ( x * 100 ) ; } , [ ] ( ld x ) { return sinh ( x ) / 100 ; } , false } ;
2023-08-09 12:01:24 +00:00
/** extendable dialog */
2023-08-09 12:22:32 +00:00
struct extdialog : funbase {
2023-08-09 12:01:24 +00:00
string title , help ;
int dialogflags ;
reaction_t reaction ;
reaction_t reaction_final ;
reaction_t extra_options ;
virtual void draw ( ) = 0 ;
void operator ( ) ( ) { draw ( ) ; }
virtual ~ extdialog ( ) { } ;
extdialog ( ) ;
/** Pop screen, then call the final reaction. A bit more complex because it eeds to backup reaction_final due to popScreen */
void popfinal ( ) { auto rf = std : : move ( reaction_final ) ; popScreen ( ) ; if ( rf ) rf ( ) ; }
} ;
/** number dialog */
struct number_dialog : extdialog {
2019-08-09 19:00:52 +00:00
ld * editwhat ;
string s ;
ld vmin , vmax , step , dft ;
scaler sc ;
int * intval ; ld intbuf ;
bool animatable ;
2024-05-27 13:21:31 +00:00
bool * boolval ;
2023-08-09 12:01:24 +00:00
void draw ( ) override ;
void apply_edit ( ) ;
void apply_slider ( ) ;
2023-08-09 12:22:32 +00:00
string disp ( ld x ) ;
void reset_str ( ) { s = disp ( * editwhat ) ; }
2019-08-09 19:00:52 +00:00
} ;
2024-05-27 13:21:31 +00:00
/** bool dialog */
struct bool_dialog : extdialog {
bool * editwhat , dft ;
reaction_t switcher ;
void draw ( ) override ;
} ;
2023-08-09 12:01:24 +00:00
# endif
2017-03-23 10:53:57 +00:00
2023-08-09 12:01:24 +00:00
EX number_dialog & get_ne ( ) {
2023-08-09 12:22:32 +00:00
auto ptr = dynamic_cast < number_dialog * > ( screens . back ( ) . target_base ( ) ) ;
2023-08-09 12:01:24 +00:00
if ( ! ptr ) throw hr_exception ( " get_ne() called without number dialog " ) ;
return * ptr ;
}
2018-09-05 13:18:40 +00:00
2023-08-09 12:01:24 +00:00
EX extdialog & get_di ( ) {
2023-08-09 12:22:32 +00:00
auto ptr = dynamic_cast < extdialog * > ( screens . back ( ) . target_base ( ) ) ;
2023-08-09 12:01:24 +00:00
if ( ! ptr ) throw hr_exception ( " get_di() called without extdialog " ) ;
return * ptr ;
}
EX void scaleLog ( ) { get_ne ( ) . sc = logarithmic ; }
EX void scaleSinh ( ) { get_ne ( ) . sc = asinhic ; }
EX void scaleSinh100 ( ) { get_ne ( ) . sc = asinhic100 ; }
2019-08-09 19:00:52 +00:00
EX color_t dialogcolor = 0xC0C0C0 ;
2022-12-04 14:24:42 +00:00
EX color_t dialogcolor_clicked = 0xFF8000 ;
EX color_t dialogcolor_selected = 0xFFD500 ;
EX color_t dialogcolor_key = 0x808080 ;
EX color_t dialogcolor_value = 0x80A040 ;
EX color_t dialogcolor_off = 0x40FF40 ;
EX color_t dialogcolor_on = 0xC04040 ;
EX color_t dialogcolor_big = 0xC06000 ;
/** pick the correct dialogcolor, based on whether mouse is over */
EX color_t dialogcolor_over ( bool b ) {
if ( ! b ) return dialogcolor ;
if ( actonrelease ) return dialogcolor_clicked ;
return dialogcolor_selected ;
}
2019-08-09 19:00:52 +00:00
EX void addBack ( ) {
2020-10-06 19:07:12 +00:00
addItem ( XLAT ( " go back " ) ,
( cmode & sm : : NUMBER ) ? SDLK_RETURN :
ISWEB ? SDLK_BACKSPACE :
SDLK_ESCAPE ) ;
2018-06-12 22:00:01 +00:00
}
2019-08-09 19:00:52 +00:00
EX void addHelp ( ) {
2018-06-12 22:00:01 +00:00
addItem ( XLAT ( " help " ) , SDLK_F1 ) ;
}
2019-08-09 19:00:52 +00:00
EX namespace zoom {
2017-03-23 10:53:57 +00:00
int zoomf = 1 , shiftx , shifty ;
bool zoomoff = false ;
2018-07-22 10:54:05 +00:00
void nozoom ( ) {
zoomf = 1 ; shiftx = 0 ; shifty = 0 ; zoomoff = false ;
2017-03-23 10:53:57 +00:00
}
2018-07-22 10:54:05 +00:00
void initzoom ( ) {
2017-03-23 10:53:57 +00:00
zoomf = 3 ;
shiftx = - 2 * mousex ;
2018-07-22 10:54:05 +00:00
if ( mousex < vid . xres / 6 ) shiftx = 0 ;
if ( mousex > vid . xres * 5 / 6 ) shiftx = - 2 * vid . xres ;
2017-03-23 10:53:57 +00:00
shifty = - 2 * mousey ;
2018-07-22 10:54:05 +00:00
if ( mousey < vid . yres / 6 ) shifty = 0 ;
if ( mousey > vid . yres * 5 / 6 ) shifty = - 2 * vid . yres ;
}
void stopzoom ( ) { zoomoff = true ; }
2019-08-09 19:00:52 +00:00
EX bool displayfr ( int x , int y , int b , int size , const string & s , color_t color , int align ) {
2018-07-22 10:54:05 +00:00
return hr : : displayfr ( x * zoomf + shiftx , y * zoomf + shifty , b , size * zoomf , s , color , align ) ;
}
2019-08-09 19:00:52 +00:00
EX bool displayfr_highlight ( int x , int y , int b , int size , const string & s , color_t color , int align , int hicolor IS ( 0xFFFF00 ) ) {
2018-07-22 10:54:05 +00:00
bool clicked = hr : : displayfr ( x * zoomf + shiftx , y * zoomf + shifty , b , size * zoomf , s , color , align ) ;
if ( clicked ) hr : : displayfr ( x * zoomf + shiftx , y * zoomf + shifty , b , size * zoomf , s , hicolor , align ) ;
return clicked ;
2017-03-23 10:53:57 +00:00
}
2020-02-23 01:51:27 +00:00
EX }
2018-07-22 10:54:05 +00:00
# if CAP_MENUSCALING && CAP_SDL
2019-08-09 19:00:52 +00:00
EX void handleZooming ( SDL_Event & ev ) {
2018-07-22 10:54:05 +00:00
using namespace zoom ;
if ( zoomoff | | ! ( cmode & sm : : ZOOMABLE ) ) {
nozoom ( ) ; return ;
2017-03-23 10:53:57 +00:00
}
2018-07-22 10:54:05 +00:00
if ( ev . type = = SDL_MOUSEBUTTONDOWN ) initzoom ( ) ;
if ( ev . type = = SDL_MOUSEBUTTONUP & & zoomf > 1 ) stopzoom ( ) ;
2017-03-23 10:53:57 +00:00
}
2019-09-06 06:17:02 +00:00
# endif
# if !(CAP_MENUSCALING && CAP_SDL)
2019-08-09 19:00:52 +00:00
EX void handleZooming ( SDL_Event & ev ) { }
2017-03-23 10:53:57 +00:00
# endif
2019-08-09 19:00:52 +00:00
EX vector < item > items ;
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX item & lastItem ( ) { return items [ items . size ( ) - 1 ] ; }
2019-11-24 22:40:26 +00:00
EX item & titleItem ( ) { return items [ 0 ] ; }
2017-03-23 10:53:57 +00:00
2024-06-17 23:04:48 +00:00
EX map < key_type , reaction_t > key_actions ;
2018-07-09 16:11:49 +00:00
2024-06-17 23:04:48 +00:00
EX void add_key_action ( key_type key , const reaction_t & action ) {
2018-07-09 16:11:49 +00:00
key_actions [ key ] = action ;
}
2019-08-14 07:14:52 +00:00
2024-06-17 23:04:48 +00:00
EX void add_key_action_adjust ( key_type & key , const reaction_t & action ) {
2019-08-14 07:14:52 +00:00
while ( key_actions . count ( key ) ) key + + ;
add_key_action ( key , action ) ;
}
2021-02-06 01:55:51 +00:00
EX void extend ( ) {
items . back ( ) . key = items [ isize ( items ) - 2 ] . key ;
}
2019-08-09 19:00:52 +00:00
EX void add_action ( const reaction_t & action ) {
2019-08-14 07:14:52 +00:00
add_key_action_adjust ( lastItem ( ) . key , action ) ;
2018-12-14 12:26:17 +00:00
}
2018-07-09 16:11:49 +00:00
2019-08-09 19:00:52 +00:00
EX void add_action_push ( const reaction_t & action ) { add_action ( [ action ] { pushScreen ( action ) ; } ) ; }
2019-03-30 22:45:28 +00:00
2021-03-06 10:00:36 +00:00
EX void add_action_push_clear ( const reaction_t & action ) { add_action ( [ action ] { clearMessages ( ) ; pushScreen ( action ) ; } ) ; }
2019-08-09 19:00:52 +00:00
EX void handler ( int sym , int uni ) {
2022-10-27 08:33:06 +00:00
if ( cmode & sm : : PANNING ) handlePanning ( sym , uni ) ;
2018-07-09 16:11:49 +00:00
dialog : : handleNavigation ( sym , uni ) ;
if ( doexiton ( sym , uni ) ) popScreen ( ) ;
2020-02-23 01:51:27 +00:00
}
2018-07-09 16:11:49 +00:00
2022-10-21 08:19:22 +00:00
EX int list_size_min , list_size_max , list_fake_key ;
2022-12-04 13:46:50 +00:00
EX const int first_list_fake_key = 10000 ;
2022-10-21 08:19:22 +00:00
2019-08-09 19:00:52 +00:00
EX void init ( ) {
2022-10-21 08:19:22 +00:00
list_size_min = list_size_max = 0 ;
2022-12-04 13:46:50 +00:00
list_fake_key = first_list_fake_key ;
2018-07-09 16:11:49 +00:00
items . clear ( ) ;
key_actions . clear ( ) ;
keyhandler = dialog : : handler ;
}
2017-03-23 10:53:57 +00:00
2024-06-17 23:04:48 +00:00
EX string keyname ( key_type k ) {
2017-03-23 10:53:57 +00:00
if ( k = = 0 ) return " " ;
if ( k = = SDLK_ESCAPE ) return " Esc " ;
2018-04-10 03:19:49 +00:00
if ( k = = SDLK_F1 ) return " F1 " ;
2024-05-28 13:15:41 +00:00
if ( k = = SDLK_F2 ) return " F2 " ;
2022-11-03 18:31:28 +00:00
if ( k = = SDLK_F3 ) return " F3 " ;
2024-05-28 13:15:41 +00:00
if ( k = = SDLK_F4 ) return " F4 " ;
if ( k = = SDLK_F5 ) return " F5 " ;
if ( k = = SDLK_F6 ) return " F6 " ;
if ( k = = SDLK_F7 ) return " F7 " ;
if ( k = = SDLK_F8 ) return " F8 " ;
if ( k = = SDLK_F9 ) return " F9 " ;
if ( k = = SDLK_F10 ) return " F10 " ;
2022-10-27 10:50:59 +00:00
if ( k > = 10000 & & k < 10500 ) return " " ;
2017-03-23 10:53:57 +00:00
if ( k = = SDLK_HOME ) return " Home " ;
2017-04-08 15:18:29 +00:00
if ( k = = SDLK_BACKSPACE ) return " Backspace " ;
if ( k = = SDLK_RETURN ) return " Enter " ;
2017-03-23 10:53:57 +00:00
if ( k = = 32 ) return " space " ;
if ( k > = 1 & & k < = 26 ) { string s = " Ctrl+ " ; s + = ( k + 64 ) ; return s ; }
if ( k < 128 ) { string s ; s + = k ; return s ; }
2020-09-15 18:39:15 +00:00
if ( k = = 508 ) return " Alt+8 " ;
2017-03-23 10:53:57 +00:00
return " ? " ;
}
2022-12-04 14:24:42 +00:00
item : : item ( tDialogItem t ) {
type = t ;
color = dialogcolor ;
colorc = dialogcolor_clicked ;
colors = dialogcolor_selected ;
colork = dialogcolor_key ;
colorv = dialogcolor_value ;
scale = 100 ;
}
2024-06-17 23:04:48 +00:00
EX void addSlider ( double d1 , double d2 , double d3 , key_type key ) {
2022-12-04 14:24:42 +00:00
item it ( diSlider ) ;
2017-03-23 10:53:57 +00:00
it . key = key ;
it . param = ( d2 - d1 ) / ( d3 - d1 ) ;
items . push_back ( it ) ;
}
2024-06-17 23:04:48 +00:00
EX void addIntSlider ( int d1 , int d2 , int d3 , key_type key ) {
2022-12-04 14:24:42 +00:00
item it ( diIntSlider ) ;
2019-05-21 22:03:51 +00:00
it . key = key ;
it . p1 = ( d2 - d1 ) ;
it . p2 = ( d3 - d1 ) ;
items . push_back ( it ) ;
}
2024-06-17 23:04:48 +00:00
EX void addSelItem ( string body , string value , key_type key ) {
2022-12-04 14:24:42 +00:00
item it ( diItem ) ;
2017-03-23 10:53:57 +00:00
it . body = body ;
it . value = value ;
it . key = key ;
2022-12-04 14:24:42 +00:00
if ( value = = ONOFF ( true ) ) it . colorv = dialogcolor_off ;
if ( value = = ONOFF ( false ) ) it . colorv = dialogcolor_on ;
2017-03-23 10:53:57 +00:00
items . push_back ( it ) ;
}
2024-06-17 23:04:48 +00:00
EX void addBoolItem ( string body , bool value , key_type key ) {
2017-03-23 10:53:57 +00:00
addSelItem ( body , ONOFF ( value ) , key ) ;
}
2017-12-21 23:51:55 +00:00
2019-08-09 21:53:20 +00:00
EX int displaycolor ( color_t col ) {
2017-12-21 23:51:55 +00:00
int c = col > > 8 ;
if ( ! c ) return 0x181818 ;
return c ;
}
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX void addKeyboardItem ( string keys ) {
2022-12-04 14:24:42 +00:00
item it ( diKeyboard ) ;
2019-07-03 05:31:09 +00:00
it . body = keys ;
2019-07-03 06:06:42 +00:00
it . scale = 150 ;
2019-07-03 05:31:09 +00:00
items . push_back ( it ) ;
}
2022-04-16 11:58:26 +00:00
EX void addCustom ( int size , reaction_t custom ) {
2022-12-04 14:24:42 +00:00
item it ( diCustom ) ;
2022-04-16 11:58:26 +00:00
it . scale = size ;
it . customfun = custom ;
items . push_back ( it ) ;
}
2024-06-17 23:04:48 +00:00
EX void addColorItem ( string body , int value , key_type key ) {
2022-07-05 10:54:59 +00:00
addSelItem ( body , COLORBAR , key ) ;
auto & it = items . back ( ) ;
it . type = diColorItem ;
it . colorv = displaycolor ( value ) ;
it . param = value & 0xFF ;
2017-03-23 10:53:57 +00:00
}
2023-08-08 15:20:39 +00:00
ld as_degrees ( transmatrix T ) {
hyperpoint h = T * point31 ( 1 , 0 , 0 ) ;
2023-08-14 15:44:22 +00:00
ld alpha = atan2 ( - h [ 1 ] , h [ 0 ] ) ;
if ( alpha = = 0 ) alpha = 0 ;
2023-08-08 15:20:39 +00:00
return alpha / degree ;
}
2024-06-17 23:04:48 +00:00
EX void addMatrixItem ( string body , transmatrix & value , key_type key , int dim IS ( GDIM ) ) {
2023-08-08 15:20:39 +00:00
addSelItem ( body , COLORBAR , key ) ;
auto & it = items . back ( ) ;
it . type = diMatrixItem ;
it . ptr = & value ;
2023-08-15 15:25:00 +00:00
it . value = " " ;
if ( dim = = 2 ) it . value = fts ( as_degrees ( value ) ) + " ° " ;
if ( dim = = 3 ) {
for ( int k = 0 ; k < 3 ; k + + ) {
if ( value [ k ] [ k ] ! = 1 ) continue ;
int i = ( k + 1 ) % 3 ;
int j = ( i + 1 ) % 3 ;
if ( i > j ) swap ( i , j ) ;
hyperpoint h = Hypc ; h [ i ] = 1 ;
h = value * h ;
ld alpha = atan2 ( - h [ j ] , h [ i ] ) ;
if ( alpha = = 0 ) alpha = 0 ;
it . value = fts ( alpha / degree ) + " ° " ;
it . value + = ( ' X ' + i ) ;
it . value + = ( ' X ' + j ) ;
}
if ( eqmatrix ( value , Id ) ) it . value = " Id " ;
}
2023-08-10 12:38:59 +00:00
it . p1 = dim ;
2023-08-08 15:20:39 +00:00
}
2019-08-09 19:00:52 +00:00
EX void addHelp ( string body ) {
2022-12-04 14:24:42 +00:00
item it ( diHelp ) ;
2017-03-23 10:53:57 +00:00
it . body = body ;
2018-06-22 12:47:24 +00:00
if ( isize ( body ) > = 500 ) it . scale = 70 ;
2017-03-23 10:53:57 +00:00
items . push_back ( it ) ;
}
2019-08-09 19:00:52 +00:00
EX void addInfo ( string body , color_t color IS ( dialogcolor ) ) {
2022-12-04 14:24:42 +00:00
item it ( diInfo ) ;
2017-03-23 10:53:57 +00:00
it . body = body ;
2022-12-17 23:29:28 +00:00
it . color = color ;
2017-03-23 10:53:57 +00:00
items . push_back ( it ) ;
}
2024-06-17 23:04:48 +00:00
EX void addItem ( string body , key_type key ) {
2022-12-04 14:24:42 +00:00
item it ( diItem ) ;
2017-03-23 10:53:57 +00:00
it . body = body ;
it . key = key ;
items . push_back ( it ) ;
}
2024-06-17 23:04:48 +00:00
EX void addBigItem ( string body , key_type key ) {
2022-12-04 14:24:42 +00:00
item it ( diBigItem ) ;
2017-08-06 12:50:16 +00:00
it . body = body ;
it . key = key ;
2022-12-04 14:24:42 +00:00
it . color = dialogcolor_big ;
2017-08-06 12:50:16 +00:00
it . scale = 150 ;
items . push_back ( it ) ;
}
2019-08-09 19:00:52 +00:00
EX int addBreak ( int val ) {
2022-12-04 14:24:42 +00:00
item it ( diBreak ) ;
2017-03-23 10:53:57 +00:00
it . scale = val ;
items . push_back ( it ) ;
2017-07-04 13:38:33 +00:00
return items . size ( ) - 1 ;
2017-03-23 10:53:57 +00:00
}
2022-10-21 08:19:22 +00:00
EX void start_list ( int size_min , int size_max , int key_start IS ( 0 ) ) {
2022-12-04 14:24:42 +00:00
item it ( diListStart ) ;
2022-10-21 08:19:22 +00:00
it . key = key_start ;
it . scale = 0 ;
it . param = size_min ;
list_size_min = size_min ;
list_size_max = size_max ;
items . push_back ( it ) ;
}
EX void end_list ( ) {
2022-12-04 14:24:42 +00:00
item it ( diListEnd ) ;
2022-10-21 08:19:22 +00:00
it . scale = 0 ;
items . push_back ( it ) ;
}
2019-08-09 19:00:52 +00:00
EX void addTitle ( string body , color_t color , int scale ) {
2022-12-04 14:24:42 +00:00
item it ( diTitle ) ;
2017-03-23 10:53:57 +00:00
it . body = body ;
it . color = color ;
it . scale = scale ;
items . push_back ( it ) ;
}
2019-08-09 19:00:52 +00:00
EX void init ( string title , color_t color IS ( 0xE8E8E8 ) , int scale IS ( 150 ) , int brk IS ( 60 ) ) {
2017-03-23 10:53:57 +00:00
init ( ) ;
addTitle ( title , color , scale ) ;
addBreak ( brk ) ;
}
2019-08-09 19:00:52 +00:00
EX int dcenter , dwidth ;
2017-04-04 09:13:15 +00:00
2019-08-09 19:00:52 +00:00
EX int displayLong ( string str , int siz , int y , bool measure ) {
2017-03-23 10:53:57 +00:00
int last = 0 ;
int lastspace = 0 ;
2017-04-04 09:13:15 +00:00
int xs , xo ;
2018-11-17 18:24:02 +00:00
if ( current_display - > sidescreen )
2017-04-08 15:18:29 +00:00
xs = dwidth - vid . fsize * 2 , xo = vid . yres + vid . fsize ;
2017-04-04 09:13:15 +00:00
else
xs = vid . xres * 618 / 1000 , xo = vid . xres * 186 / 1000 ;
2017-03-23 10:53:57 +00:00
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < = isize ( str ) ; i + + ) {
2017-03-23 10:53:57 +00:00
int ls = 0 ;
int prev = last ;
if ( str [ i ] = = ' ' ) lastspace = i ;
if ( textwidth ( siz , str . substr ( last , i - last ) ) > xs ) {
if ( lastspace = = last ) ls = i - 1 , last = i - 1 ;
else ls = lastspace , last = ls + 1 ;
}
2018-06-22 12:47:24 +00:00
if ( str [ i ] = = 10 | | i = = isize ( str ) ) ls = i , last = i + 1 ;
2017-03-23 10:53:57 +00:00
if ( ls ) {
2018-09-05 13:18:40 +00:00
if ( ! measure ) displayfr ( xo , y , 2 , siz , str . substr ( prev , ls - prev ) , dialogcolor , 0 ) ;
2017-03-23 10:53:57 +00:00
if ( ls = = prev ) y + = siz / 2 ;
else y + = siz ;
lastspace = last ;
}
}
y + = siz / 2 ;
return y ;
}
2017-04-04 09:13:15 +00:00
2022-10-21 17:03:03 +00:00
EX int tothei , dialogwidth , dfsize , dfspace , odfspace , leftwidth , rightwidth , innerwidth , itemx , keyx , valuex , top , list_starts_at , list_ends_at , list_full_size , list_actual_size , list_skip , fwidth ;
2022-10-21 08:19:22 +00:00
2019-09-06 06:17:02 +00:00
EX string highlight_text ;
2022-10-21 08:19:22 +00:00
EX int highlight_key ;
2022-11-03 18:29:23 +00:00
EX bool is_highlight ( item & I ) { return I . body = = highlight_text & & among ( highlight_key , I . key , PSEUDOKEY_SELECT ) ; }
2022-10-21 08:19:22 +00:00
EX void set_highlight ( item & I ) { highlight_text = I . body ; highlight_key = I . key ; }
2022-11-03 18:29:23 +00:00
EX void find_highlight ( const string & s ) {
println ( hlog , " highlight_text set to " , s ) ;
highlight_text = s ; highlight_key = PSEUDOKEY_SELECT ;
}
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX void measure ( ) {
2017-03-23 10:53:57 +00:00
tothei = 0 ;
dialogwidth = 0 ;
innerwidth = 0 ;
int N = items . size ( ) ;
2022-10-21 08:19:22 +00:00
list_starts_at = list_ends_at = list_actual_size = 0 ;
2022-10-21 16:50:30 +00:00
bool autoval = cmode & sm : : AUTO_VALUES ;
rightwidth = 0 ;
if ( ! autoval ) rightwidth = textwidth ( dfsize , " MMMMMMMM " ) + dfsize / 2 ;
2022-11-03 18:31:06 +00:00
if ( cmode & sm : : DIALOG_WIDE )
innerwidth = textwidth ( dfsize , " MMMMM " ) * 7 ;
2022-10-21 16:50:30 +00:00
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < N ; i + + ) {
2022-10-21 08:19:22 +00:00
if ( items [ i ] . type = = diListStart )
list_starts_at = tothei ;
else if ( items [ i ] . type = = diListEnd ) {
list_full_size = tothei - list_starts_at ;
2022-10-21 17:03:03 +00:00
list_actual_size = min ( odfspace * list_size_max / 100 , max ( odfspace * list_size_min / 100 , list_full_size ) ) ;
2022-10-21 08:19:22 +00:00
if ( list_full_size < list_actual_size ) list_full_size = list_actual_size ;
tothei = list_ends_at = list_starts_at + list_actual_size ;
}
else if ( items [ i ] . type = = diHelp )
2017-03-23 10:53:57 +00:00
tothei + = displayLong ( items [ i ] . body , dfsize * items [ i ] . scale / 100 , 0 , true ) ;
else {
tothei + = dfspace * items [ i ] . scale / 100 ;
2022-07-05 10:54:59 +00:00
if ( among ( items [ i ] . type , diItem , diColorItem ) )
2017-03-23 10:53:57 +00:00
innerwidth = max ( innerwidth , textwidth ( dfsize * items [ i ] . scale / 100 , items [ i ] . body ) ) ;
2022-10-21 16:50:30 +00:00
if ( among ( items [ i ] . type , diItem ) )
rightwidth = max ( rightwidth , textwidth ( dfsize * items [ i ] . scale / 100 , items [ i ] . value ) + dfsize ) ;
2017-08-06 12:50:16 +00:00
if ( items [ i ] . type = = diTitle | | items [ i ] . type = = diInfo | | items [ i ] . type = = diBigItem )
2017-03-23 10:53:57 +00:00
dialogwidth = max ( dialogwidth , textwidth ( dfsize * items [ i ] . scale / 100 , items [ i ] . body ) * 10 / 9 ) ;
}
}
leftwidth = ISMOBILE ? 0 : textwidth ( dfsize , " MMMMM " ) + dfsize / 2 ;
2022-10-21 08:19:22 +00:00
fwidth = innerwidth + leftwidth + rightwidth ;
if ( list_actual_size ) fwidth + = dfsize ;
2017-03-23 10:53:57 +00:00
dialogwidth = max ( dialogwidth , fwidth ) ;
2017-04-04 09:13:15 +00:00
itemx = dcenter - fwidth / 2 + leftwidth ;
keyx = dcenter - fwidth / 2 + leftwidth - dfsize / 2 ;
valuex = dcenter - fwidth / 2 + leftwidth + innerwidth + dfsize / 2 ;
2017-03-23 10:53:57 +00:00
}
2019-09-08 08:08:05 +00:00
EX purehookset hooks_display_dialog ;
2020-11-19 17:20:06 +00:00
EX vector < int > key_queue ;
EX void queue_key ( int key ) { key_queue . push_back ( key ) ; }
2022-07-05 10:54:59 +00:00
EX int uishape ( ) {
int a = S7 ;
if ( a < 3 ) a = 3 ;
if ( a > 36 ) a = 36 ;
return a ;
}
2022-10-21 08:19:22 +00:00
EX void draw_list_slider ( int x , int yt ) {
int a = uishape ( ) ;
flat_model_enabler fme ;
initquickqueue ( ) ;
ld pix = 1 / ( 2 * cgi . hcrossf / cgi . crossf ) ;
shiftmatrix V = shiftless ( atscreenpos ( 0 , 0 , pix ) ) ;
color_t col = 0xFFFFFFFF ;
ld siz = dfsize / 2 ;
ld si = siz / 2 ;
int yb = yt + list_actual_size ;
curvepoint ( hyperpoint ( x - si , yt , 1 , 1 ) ) ;
for ( int i = 0 ; i < = a / 2 ; i + + )
2022-11-12 21:38:45 +00:00
curvepoint ( hyperpoint ( x - si * cos ( i * TAU / a ) , yb + si * sin ( i * TAU / a ) , 1 , 1 ) ) ;
2022-10-21 08:19:22 +00:00
for ( int i = ( a + 1 ) / 2 ; i < = a ; i + + )
2022-11-12 21:38:45 +00:00
curvepoint ( hyperpoint ( x - si * cos ( i * TAU / a ) , yt + si * sin ( i * TAU / a ) , 1 , 1 ) ) ;
2022-10-21 08:19:22 +00:00
queuecurve ( V , col , 0x80 , PPR : : LINE ) ;
int yt1 = yt + ( list_actual_size * list_skip ) / list_full_size ;
int yb1 = yt + ( list_actual_size * ( list_skip + list_actual_size ) ) / list_full_size ;
curvepoint ( hyperpoint ( x - siz , yt1 , 1 , 1 ) ) ;
for ( int i = 0 ; i < = a / 2 ; i + + )
2022-11-12 21:38:45 +00:00
curvepoint ( hyperpoint ( x - siz * cos ( i * TAU / a ) , yb1 + siz * sin ( i * TAU / a ) , 1 , 1 ) ) ;
2022-10-21 08:19:22 +00:00
for ( int i = ( a + 1 ) / 2 ; i < = a ; i + + )
2022-11-12 21:38:45 +00:00
curvepoint ( hyperpoint ( x - siz * cos ( i * TAU / a ) , yt1 + siz * sin ( i * TAU / a ) , 1 , 1 ) ) ;
2022-10-21 08:19:22 +00:00
queuecurve ( V , col , 0x80 , PPR : : LINE ) ;
quickqueue ( ) ;
}
2022-07-05 10:26:20 +00:00
EX void draw_slider ( int sl , int sr , int y , item & I ) {
int sw = sr - sl ;
int mid = y ;
if ( ! wmascii ) {
2022-07-05 10:54:59 +00:00
int a = uishape ( ) ;
2022-07-05 10:26:20 +00:00
flat_model_enabler fme ;
initquickqueue ( ) ;
ld pix = 1 / ( 2 * cgi . hcrossf / cgi . crossf ) ;
shiftmatrix V = shiftless ( atscreenpos ( 0 , 0 , pix ) ) ;
2022-07-05 10:54:59 +00:00
color_t col = addalpha ( I . color ) ;
2022-07-05 10:26:20 +00:00
ld siz = dfsize * I . scale / 150 ;
ld si = siz / 2 ;
if ( I . type = = diIntSlider & & I . p2 < sw / 4 ) {
for ( int a = 0 ; a < = I . p2 ; a + + ) {
ld x = sl + sw * a * 1. / I . p2 ;
curvepoint ( hyperpoint ( x , y - si , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( x , y + si , 1 , 1 ) ) ;
queuecurve ( V , col , 0 , PPR : : LINE ) ;
}
}
curvepoint ( hyperpoint ( sl , y - si , 1 , 1 ) ) ;
for ( int i = 0 ; i < = a / 2 ; i + + )
2022-11-12 21:38:45 +00:00
curvepoint ( hyperpoint ( sr + si * sin ( i * TAU / a ) , y - si * cos ( i * TAU / a ) , 1 , 1 ) ) ;
2022-07-05 10:26:20 +00:00
for ( int i = ( a + 1 ) / 2 ; i < = a ; i + + )
2022-11-12 21:38:45 +00:00
curvepoint ( hyperpoint ( sl + si * sin ( i * TAU / a ) , y - si * cos ( i * TAU / a ) , 1 , 1 ) ) ;
2022-07-05 10:26:20 +00:00
queuecurve ( V , col , 0x80 , PPR : : LINE ) ;
quickqueue ( ) ;
ld x = sl + sw * ( I . type = = diIntSlider ? I . p1 * 1. / I . p2 : I . param ) ;
if ( x < sl - si ) {
curvepoint ( hyperpoint ( sl - si , y , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( x , y , 1 , 1 ) ) ;
queuecurve ( V , col , 0x80 , PPR : : LINE ) ;
quickqueue ( ) ;
}
if ( x > sr + si ) {
curvepoint ( hyperpoint ( sr + si , y , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( x , y , 1 , 1 ) ) ;
queuecurve ( V , col , 0x80 , PPR : : LINE ) ;
quickqueue ( ) ;
}
2022-11-12 21:38:45 +00:00
for ( int i = 0 ; i < = a ; i + + ) curvepoint ( hyperpoint ( x + siz * sin ( i * TAU / a ) , y - siz * cos ( i * TAU / a ) , 1 , 1 ) ) ;
2022-07-05 10:26:20 +00:00
queuecurve ( V , col , col , PPR : : LINE ) ;
quickqueue ( ) ;
}
else if ( I . type = = diSlider ) {
displayfr ( sl , mid , 2 , dfsize * I . scale / 100 , " ( " , I . color , 16 ) ;
displayfr ( sl + double ( sw * I . param ) , mid , 2 , dfsize * I . scale / 100 , " # " , I . color , 8 ) ;
displayfr ( sr , mid , 2 , dfsize * I . scale / 100 , " ) " , I . color , 0 ) ;
}
else {
displayfr ( sl , mid , 2 , dfsize * I . scale / 100 , " { " , I . color , 16 ) ;
if ( I . p2 < sw / 4 ) for ( int a = 0 ; a < = I . p2 ; a + + ) if ( a ! = I . p1 )
displayfr ( sl + double ( sw * a / I . p2 ) , mid , 2 , dfsize * I . scale / 100 , a = = I . p1 ? " # " : " . " , I . color , 8 ) ;
displayfr ( sl + double ( sw * I . p1 / I . p2 ) , mid , 2 , dfsize * I . scale / 100 , " # " , I . color , 8 ) ;
displayfr ( sr , mid , 2 , dfsize * I . scale / 100 , " } " , I . color , 0 ) ;
}
}
2023-08-15 15:25:00 +00:00
EX void visualize_matrix ( const trans23 & T , ld x , ld y , ld r , int dim , ld tsize ) {
2023-08-09 07:07:53 +00:00
vector < hyperpoint > pts ;
2023-08-10 12:38:59 +00:00
for ( int a = 0 ; a < dim ; a + + ) {
2023-08-09 07:07:53 +00:00
hyperpoint h = C0 ; h [ a ] = r ;
2023-08-14 08:52:17 +00:00
pts . push_back ( T . get ( ) * h ) ;
2023-08-09 07:07:53 +00:00
}
flat_model_enabler fme ;
initquickqueue ( ) ;
ld pix = 1 / ( 2 * cgi . hcrossf / cgi . crossf ) ;
shiftmatrix V = shiftless ( atscreenpos ( x , y , pix ) ) ;
for ( int i = 0 ; i < = 360 ; i + + )
curvepoint ( hyperpoint ( r * sin ( i * degree ) , r * cos ( i * degree ) , 1 , 1 ) ) ;
queuecurve ( V , 0xFFFFFFFF , 0x202020FF , PPR : : LINE ) ;
2023-08-15 15:25:00 +00:00
color_t cols [ 3 ] = { 0xFF8080FF , 0x80FF80FF , 0x8080FFFF } ;
2023-08-10 12:38:59 +00:00
for ( int a = 0 ; a < dim ; a + + ) {
2023-08-09 12:23:10 +00:00
auto pt = pts [ a ] ; pt [ 2 ] = 1 ; pt [ 3 ] = 1 ;
2023-08-09 07:07:53 +00:00
curvepoint ( hyperpoint ( 0 , 0 , 1 , 1 ) ) ;
curvepoint ( pt ) ;
// queueline(V * hyperpoint(0,0,1,1), V * pt, cols[a], 0);
queuecurve ( V , cols [ a ] , 0 , PPR : : LINE ) ;
}
2023-08-14 02:36:23 +00:00
if ( dim = = 3 ) for ( int a = 0 ; a < dim ; a + + ) {
2023-08-15 15:25:00 +00:00
auto pt = pts [ a ] ; ld val = - pt [ 2 ] * tsize / r / 5 ;
2023-08-14 02:36:23 +00:00
curvepoint ( hyperpoint ( pt [ 0 ] , pt [ 1 ] + val , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( pt [ 0 ] - val , pt [ 1 ] - val * sqrt ( 3 ) / 2 , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( pt [ 0 ] + val , pt [ 1 ] - val * sqrt ( 3 ) / 2 , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( pt [ 0 ] , pt [ 1 ] + val , 1 , 1 ) ) ;
queuecurve ( V , cols [ a ] , cols [ a ] & 0xFFFFFF80 , PPR : : LINE ) ;
2023-08-09 07:07:53 +00:00
}
quickqueue ( ) ;
}
2024-06-27 20:22:06 +00:00
EX void draw_side_shade ( ) {
int steps = menu_darkening - darken ;
color_t col = ( backcolor < < 8 ) | ( 255 - ( 255 > > steps ) ) ;
if ( svg : : in | | ! ( auraNOGL | | vid . usingGL ) ) {
flat_model_enabler fme ;
initquickqueue ( ) ;
ld pix = 1 / ( 2 * cgi . hcrossf / cgi . crossf ) ;
curvepoint ( hyperpoint ( vid . xres - dwidth , - 10 , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( vid . xres + 10 , - 10 , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( vid . xres + 10 , vid . yres + 10 , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( vid . xres - dwidth , vid . yres + 10 , 1 , 1 ) ) ;
curvepoint ( hyperpoint ( vid . xres - dwidth , - 10 , 1 , 1 ) ) ;
shiftmatrix V = shiftless ( atscreenpos ( 0 , 0 , pix ) ) ;
queuecurve ( V , 0 , col , PPR : : LINE ) ;
quickqueue ( ) ;
}
# if CAP_GL
else {
auto full = part ( col , 0 ) ;
static vector < glhr : : colored_vertex > auravertices ;
auravertices . clear ( ) ;
ld width = vid . xres / 100 ;
for ( int i = 4 ; i < steps & & i < 8 ; i + + ) width / = sqrt ( 2 ) ;
for ( int x = 0 ; x < 16 ; x + + ) {
for ( int c = 0 ; c < 6 ; c + + ) {
int bx = ( c = = 1 | | c = = 3 | | c = = 5 ) ? x + 1 : x ;
int by = ( c = = 2 | | c = = 4 | | c = = 5 ) ? vid . yres : 0 ;
int cx = bx = = 0 ? 0 : bx = = 16 ? vid . xres :
vid . xres - dwidth + width * tan ( ( bx - 8 ) / 8. * 90. _deg ) ;
part ( col , 0 ) = lerp ( 0 , full , bx / 16. ) ;
auravertices . emplace_back ( hyperpoint ( cx - current_display - > xcenter , by - current_display - > ycenter , 0 , 1 ) , col ) ;
}
}
glflush ( ) ;
current_display - > next_shader_flags = GF_VARCOLOR ;
dynamicval < eModel > m ( pmodel , mdPixel ) ;
current_display - > set_all ( 0 , 0 ) ;
glhr : : id_modelview ( ) ;
glhr : : prepare ( auravertices ) ;
glhr : : set_depthtest ( false ) ;
glDrawArrays ( GL_TRIANGLES , 0 , isize ( auravertices ) ) ;
}
# endif
}
2019-08-09 19:00:52 +00:00
EX void display ( ) {
2020-11-19 17:20:06 +00:00
2019-09-08 08:08:05 +00:00
callhooks ( hooks_display_dialog ) ;
2024-07-27 16:23:01 +00:00
if ( just_refreshing ) return ;
2017-03-23 10:53:57 +00:00
int N = items . size ( ) ;
dfsize = vid . fsize ;
2017-07-22 23:33:27 +00:00
# if ISMOBILE || ISPANDORA
2017-03-23 10:53:57 +00:00
dfsize * = 3 ;
# endif
dfspace = dfsize * 5 / 4 ;
2022-10-21 17:03:03 +00:00
odfspace = dfspace ;
2017-04-04 09:13:15 +00:00
dcenter = vid . xres / 2 ;
dwidth = vid . xres ;
2017-07-12 17:50:39 +00:00
2018-11-17 18:24:02 +00:00
if ( current_display - > sidescreen ) {
2017-04-04 09:13:15 +00:00
dwidth = vid . xres - vid . yres ;
2017-04-08 15:18:29 +00:00
dcenter = vid . xres - dwidth / 2 ;
2017-04-04 09:13:15 +00:00
}
2024-07-27 19:05:10 +00:00
else if ( cmode & sm : : DIALOG_OFFMAP ) {
dwidth = vid . xres / 3 ;
dcenter = vid . xres * 5 / 6 ;
}
2017-04-04 09:13:15 +00:00
2017-07-12 17:50:39 +00:00
measure ( ) ;
2017-03-23 10:53:57 +00:00
while ( tothei > vid . yres - 5 * vid . fsize ) {
int adfsize = int ( dfsize * sqrt ( ( vid . yres - 5. * vid . fsize ) / tothei ) ) ;
if ( adfsize < dfsize - 1 ) dfsize = adfsize + 1 ;
else dfsize - - ;
2022-10-21 17:03:03 +00:00
odfspace = dfspace = dfsize * 5 / 4 ;
2017-03-23 10:53:57 +00:00
measure ( ) ;
}
2017-04-04 09:13:15 +00:00
while ( dialogwidth > dwidth ) {
2017-03-23 10:53:57 +00:00
int adfsize = int ( dfsize * sqrt ( vid . xres * 1. / dialogwidth ) ) ;
if ( adfsize < dfsize - 1 ) dfsize = adfsize + 1 ;
2022-10-21 17:03:03 +00:00
else dfsize - - ;
// usually we want to keep dfspace, but with NARROW_LINES, just odfspace
if ( cmode & sm : : NARROW_LINES )
dfspace = ( dfsize + 3 ) * 5 / 4 ;
2017-03-23 10:53:57 +00:00
measure ( ) ;
}
tothei = ( vid . yres - tothei ) / 2 ;
2022-10-21 08:19:22 +00:00
int list_left = list_actual_size ;
int list_next_key ;
if ( ! list_actual_size ) {
if ( list_skip ) println ( hlog , " list_skip reset " ) ;
list_skip = 0 ;
}
2017-03-23 10:53:57 +00:00
2024-06-27 20:22:06 +00:00
if ( current_display - > sidescreen & & darken < menu_darkening ) draw_side_shade ( ) ;
2022-07-05 11:57:34 +00:00
2022-10-21 08:19:22 +00:00
bool inlist = false ;
int need_to_skip = 0 ;
int list_more_skip = list_skip ;
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < N ; i + + ) {
item & I = items [ i ] ;
if ( I . type = = diHelp ) {
tothei = displayLong ( items [ i ] . body , dfsize * items [ i ] . scale / 100 , tothei , false ) ;
continue ;
}
2022-10-21 08:19:22 +00:00
int size = dfspace * I . scale / 100 ;
dynamicval < int > dkb ( I . key ) ;
bool to_highlight = is_highlight ( I ) ;
if ( I . type = = diListStart ) {
list_left = list_actual_size ;
inlist = true ;
list_next_key = I . key ;
2022-10-21 08:30:09 +00:00
list_starts_at = tothei ;
2022-10-21 08:19:22 +00:00
continue ;
}
if ( I . type = = diListEnd ) {
tothei + = list_left ;
inlist = false ;
2022-10-21 08:30:09 +00:00
list_ends_at = tothei ;
draw_list_slider ( dcenter + fwidth / 2 - dfsize / 2 , list_starts_at ) ;
2022-10-21 09:56:33 +00:00
if ( mousex > = dcenter + fwidth / 2 - dfsize & & mousey > = list_starts_at & & mousey < list_ends_at )
getcstat = PSEUDOKEY_LIST_SLIDER ;
2022-10-21 09:45:00 +00:00
if ( list_left > 0 ) {
list_skip - = list_left ;
list_skip - = list_more_skip ;
if ( list_skip < 0 ) list_skip = 0 ;
}
2022-10-21 08:19:22 +00:00
continue ;
}
if ( inlist & & list_more_skip > 0 ) {
if ( to_highlight ) {
list_skip - = list_more_skip ;
list_more_skip = 0 ;
}
else {
list_more_skip - = size ;
if ( list_more_skip < 0 ) { tothei - = list_more_skip ; list_left + = list_more_skip ; list_more_skip = 0 ; }
continue ;
}
}
if ( inlist ) {
if ( list_left < size ) {
tothei + = list_left ; size - = list_left ; need_to_skip + = size ; list_left = 0 ;
if ( to_highlight ) list_skip + = need_to_skip ;
continue ;
}
else list_left - = size ;
2023-12-12 19:09:19 +00:00
if ( list_next_key ) { if ( key_actions . count ( I . key ) ) key_actions [ list_next_key ] = key_actions [ I . key ] ; I . key = list_next_key + + ; }
2022-10-21 08:19:22 +00:00
}
2022-04-16 11:58:26 +00:00
top = tothei ;
2022-10-21 08:19:22 +00:00
tothei + = size ;
2017-03-23 10:53:57 +00:00
int mid = ( top + tothei ) / 2 ;
2017-07-04 13:38:33 +00:00
I . position = mid ;
2017-03-23 10:53:57 +00:00
if ( I . type = = diTitle | | I . type = = diInfo ) {
2019-11-24 22:40:26 +00:00
bool xthis = ( mousey > = top & & mousey < tothei & & I . key ) ;
2020-08-01 14:42:55 +00:00
if ( cmode & sm : : DIALOG_STRICT_X )
xthis = xthis & & ( mousex > = dcenter - dialogwidth / 2 & & mousex < = dcenter + dialogwidth / 2 ) ;
2017-04-04 09:13:15 +00:00
displayfr ( dcenter , mid , 2 , dfsize * I . scale / 100 , I . body , I . color , 8 ) ;
2019-11-24 22:40:26 +00:00
if ( xthis ) getcstat = I . key ;
2017-03-23 10:53:57 +00:00
}
2023-08-08 15:20:39 +00:00
else if ( among ( I . type , diItem , diBigItem , diColorItem , diMatrixItem ) ) {
2017-03-23 10:53:57 +00:00
bool xthis = ( mousey > = top & & mousey < tothei ) ;
2018-01-05 16:29:26 +00:00
if ( cmode & sm : : DIALOG_STRICT_X )
2017-12-14 01:51:31 +00:00
xthis = xthis & & ( mousex > = dcenter - dialogwidth / 2 & & mousex < = dcenter + dialogwidth / 2 ) ;
2017-07-22 23:33:27 +00:00
# if ISMOBILE
2017-03-23 10:53:57 +00:00
if ( xthis & & mousepressed )
I . color = I . colorc ;
# else
if ( xthis & & mousemoved ) {
2022-10-21 08:19:22 +00:00
set_highlight ( I ) ;
highlight_key = dkb . backup ;
2017-03-23 10:53:57 +00:00
mousemoved = false ;
2022-10-21 08:19:22 +00:00
to_highlight = true ;
2017-03-23 10:53:57 +00:00
}
2022-10-21 08:19:22 +00:00
if ( to_highlight ) {
2017-03-23 10:53:57 +00:00
I . color = ( xthis & & mousepressed & & actonrelease ) ? I . colorc : I . colors ;
}
# endif
2020-11-19 17:20:06 +00:00
2017-08-06 12:50:16 +00:00
if ( I . type = = diBigItem ) {
displayfr ( dcenter , mid , 2 , dfsize * I . scale / 100 , I . body , I . color , 8 ) ;
}
else {
if ( ! mousing )
2019-08-14 07:14:52 +00:00
displayfr ( keyx , mid , 2 , dfsize * I . scale / 100 , keyname ( I . key ) , I . colork , 16 ) ;
2017-08-06 12:50:16 +00:00
displayfr ( itemx , mid , 2 , dfsize * I . scale / 100 , I . body , I . color , 0 ) ;
2022-07-05 10:54:59 +00:00
if ( I . type = = diColorItem & & ! wmascii ) {
int a = uishape ( ) ;
flat_model_enabler fme ;
initquickqueue ( ) ;
ld pix = 1 / ( 2 * cgi . hcrossf / cgi . crossf ) ;
color_t col = addalpha ( I . color ) ;
ld sizf = dfsize * I . scale / 150 ;
ld siz = sizf * sqrt ( 0.15 + 0.85 * I . param / 255. ) ;
2022-11-12 21:38:45 +00:00
for ( int i = 0 ; i < = a ; i + + ) curvepoint ( hyperpoint ( siz * sin ( i * TAU / a ) , - siz * cos ( i * TAU / a ) , 1 , 1 ) ) ;
2022-07-05 10:54:59 +00:00
shiftmatrix V = shiftless ( atscreenpos ( valuex + sizf , mid , pix ) ) ;
queuecurve ( V , col , ( I . colorv < < 8 ) | 0xFF , PPR : : LINE ) ;
quickqueue ( ) ;
}
else {
int siz = dfsize * I . scale / 100 ;
2023-08-15 15:25:00 +00:00
while ( siz > 6 & & textwidth ( siz , I . value ) + ( I . type = = diMatrixItem ? siz * 3 / 2 : 0 ) > = vid . xres - valuex ) siz - - ;
displayfr ( valuex + ( I . type = = diMatrixItem ? siz * 3 / 2 : 0 ) , mid , 2 , siz , I . value , I . colorv , 0 ) ;
2023-08-09 07:07:53 +00:00
2023-08-15 15:25:00 +00:00
if ( I . type = = diMatrixItem ) visualize_matrix ( * ( ( transmatrix * ) I . ptr ) , valuex + siz / 2 , mid , siz / 2 , I . p1 , vid . fsize ) ;
2022-07-05 10:54:59 +00:00
}
2017-08-06 12:50:16 +00:00
}
2017-03-23 10:53:57 +00:00
if ( xthis ) getcstat = I . key ;
}
2019-05-21 22:03:51 +00:00
else if ( among ( I . type , diSlider , diIntSlider ) ) {
2017-03-23 10:53:57 +00:00
bool xthis = ( mousey > = top & & mousey < tothei ) ;
2017-04-04 09:13:15 +00:00
int sl , sr ;
2018-11-17 18:24:02 +00:00
if ( current_display - > sidescreen )
2017-04-04 09:13:15 +00:00
sl = vid . yres + vid . fsize * 2 , sr = vid . xres - vid . fsize * 2 ;
else
sl = vid . xres / 4 , sr = vid . xres * 3 / 4 ;
2022-07-05 10:26:20 +00:00
draw_slider ( sl , sr , mid , I ) ;
2020-11-19 17:20:06 +00:00
if ( xthis ) getcstat = I . key , inslider = true , slider_x = mousex ;
2017-03-23 10:53:57 +00:00
}
2022-04-16 11:58:26 +00:00
else if ( I . type = = diCustom ) {
I . customfun ( ) ;
}
2019-07-03 05:31:09 +00:00
else if ( I . type = = diKeyboard ) {
int len = 0 ;
for ( char c : I . body )
if ( c = = ' ' | | c = = ' \t ' ) len + = 3 ;
else len + + ;
int sl , sr ;
if ( current_display - > sidescreen )
sl = vid . yres + vid . fsize * 2 , sr = vid . xres - vid . fsize * 2 ;
else
sl = vid . xres / 4 , sr = vid . xres * 3 / 4 ;
int pos = 0 ;
for ( char c : I . body ) {
string s = " " ;
s + = c ;
int nlen = 1 ;
if ( c = = ' ' ) s = " SPACE " , nlen = 3 ;
if ( c = = ' \b ' ) s = " ⌫ " , nlen = 1 ;
if ( c = = ' \r ' | | c = = ' \n ' ) s = " ⏎ " , nlen = 1 ;
if ( c = = 1 ) s = " ← " , nlen = 1 ;
if ( c = = 2 ) s = " → " , nlen = 1 ;
if ( c = = 3 ) s = " π " ;
if ( c = = ' \t ' ) s = " CLEAR " , nlen = 3 ;
2019-07-12 21:10:57 +00:00
int left = sl + ( sr - sl ) * pos / len ;
pos + = nlen ;
int right = sl + ( sr - sl ) * pos / len ;
bool in = ( mousex > = left & & mousex < = right & & mousey > = top & & mousey < tothei ) ;
int xpos = ( left + right ) / 2 ;
if ( in ) {
2019-07-03 05:31:09 +00:00
if ( c = = 1 ) getcstat = SDLK_LEFT ;
else if ( c = = 2 ) getcstat = SDLK_RIGHT ;
else getcstat = c ;
}
2022-12-04 14:24:42 +00:00
displayfr ( xpos , mid , 2 , dfsize * I . scale / 100 , s , dialogcolor_over ( in ) , 8 ) ;
2019-07-03 05:31:09 +00:00
}
}
2017-03-23 10:53:57 +00:00
}
}
2017-08-06 12:50:16 +00:00
bool isitem ( item & it ) {
2023-08-15 15:08:25 +00:00
return among ( it . type , diItem , diBigItem , diColorItem , diMatrixItem ) ;
2017-08-06 12:50:16 +00:00
}
2020-10-06 19:07:34 +00:00
EX void handle_actions ( int & sym , int & uni ) {
if ( key_actions . count ( uni ) ) {
key_actions [ uni ] ( ) ;
sym = uni = 0 ;
return ;
}
if ( key_actions . count ( sym ) ) {
key_actions [ sym ] ( ) ;
sym = uni = 0 ;
return ;
}
}
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX void handleNavigation ( int & sym , int & uni ) {
2022-10-21 09:56:33 +00:00
if ( sym = = PSEUDOKEY_LIST_SLIDER ) invslider = true ;
if ( invslider ) {
uni = sym = 0 ;
int max = list_full_size - list_actual_size ;
list_skip = ( max * ( mousey - list_starts_at ) ) / list_actual_size ;
if ( list_skip < 0 ) list_skip = 0 ;
if ( list_skip > max ) list_skip = max ;
highlight_text = " //missing " ;
return ;
}
2020-10-06 19:07:34 +00:00
if ( uni = = ' \n ' | | uni = = ' \r ' | | DIRECTIONKEY = = SDLK_KP5 ) {
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2017-08-06 12:50:16 +00:00
if ( isitem ( items [ i ] ) )
2022-10-21 08:19:22 +00:00
if ( is_highlight ( items [ i ] ) ) {
2017-03-23 10:53:57 +00:00
uni = sym = items [ i ] . key ;
2020-10-06 19:07:34 +00:00
handle_actions ( sym , uni ) ;
2017-03-23 10:53:57 +00:00
return ;
}
2020-10-06 19:07:34 +00:00
}
2022-10-27 10:51:15 +00:00
if ( sym = = PSEUDOKEY_WHEELUP & & list_actual_size ) {
sym = 0 ;
list_skip - = 30 ;
highlight_text = " //missing " ;
}
if ( sym = = PSEUDOKEY_WHEELDOWN & & list_actual_size ) {
sym = 0 ;
list_skip + = 30 ;
highlight_text = " //missing " ;
}
2018-12-06 11:31:51 +00:00
if ( DKEY = = SDLK_PAGEDOWN ) {
2020-10-06 19:07:34 +00:00
uni = sym = 0 ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2022-10-21 08:19:22 +00:00
if ( isitem ( items [ i ] ) ) {
set_highlight ( items [ i ] ) ;
}
2017-03-23 10:53:57 +00:00
}
2018-12-06 11:31:51 +00:00
if ( DKEY = = SDLK_PAGEUP ) {
2020-10-06 19:07:34 +00:00
uni = sym = 0 ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2017-08-06 12:50:16 +00:00
if ( isitem ( items [ i ] ) ) {
2022-10-21 08:19:22 +00:00
set_highlight ( items [ i ] ) ;
2017-03-23 10:53:57 +00:00
break ;
}
}
2018-12-06 11:31:51 +00:00
if ( DKEY = = SDLK_UP ) {
2020-10-06 19:07:34 +00:00
uni = sym = 0 ;
2022-10-21 08:19:22 +00:00
dialog : : item * last = nullptr ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2022-10-21 08:19:22 +00:00
if ( isitem ( items [ i ] ) ) {
last = & ( items [ i ] ) ;
}
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2017-08-06 12:50:16 +00:00
if ( isitem ( items [ i ] ) ) {
2022-10-21 08:19:22 +00:00
if ( is_highlight ( items [ i ] ) ) {
set_highlight ( * last ) ;
return ;
2017-03-23 10:53:57 +00:00
}
2022-10-21 08:19:22 +00:00
else {
last = & ( items [ i ] ) ;
}
2017-03-23 10:53:57 +00:00
}
2023-01-04 22:24:52 +00:00
if ( last )
set_highlight ( * last ) ;
2017-03-23 10:53:57 +00:00
}
2018-12-06 11:31:51 +00:00
if ( DKEY = = SDLK_DOWN ) {
2020-10-06 19:07:34 +00:00
uni = sym = 0 ;
2017-03-23 10:53:57 +00:00
int state = 0 ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2017-08-06 12:50:16 +00:00
if ( isitem ( items [ i ] ) ) {
2022-10-21 08:19:22 +00:00
if ( state ) { set_highlight ( items [ i ] ) ; return ; }
else if ( is_highlight ( items [ i ] ) ) state = 1 ;
2017-03-23 10:53:57 +00:00
}
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( items ) ; i + + )
2020-09-16 12:23:00 +00:00
if ( isitem ( items [ i ] ) ) {
2022-10-21 08:19:22 +00:00
set_highlight ( items [ i ] ) ;
2020-09-16 12:23:00 +00:00
break ;
}
2018-07-09 16:11:49 +00:00
}
2020-10-06 19:07:34 +00:00
handle_actions ( sym , uni ) ;
2017-03-23 10:53:57 +00:00
}
2018-09-04 17:53:42 +00:00
color_t colorhistory [ 10 ] = {
2017-03-23 10:53:57 +00:00
0x202020FF , 0x800000FF , 0x008000FF , 0x000080FF ,
0x404040FF , 0xC0C0C0FF , 0x804000FF , 0xC0C000FF ,
0x408040FF , 0xFFD500FF
} , lch ;
2019-08-09 19:00:52 +00:00
EX color_t * palette ;
2017-03-23 10:53:57 +00:00
2017-05-27 19:40:40 +00:00
int colorp = 0 ;
2018-09-04 17:53:42 +00:00
color_t * colorPointer ;
2023-08-09 12:01:24 +00:00
struct color_dialog : extdialog {
void draw ( ) override ;
} ;
2017-07-10 18:47:38 +00:00
2023-08-09 12:01:24 +00:00
EX void handleKeyColor ( int sym , int uni , struct color_dialog & ne ) {
2017-07-16 21:00:55 +00:00
unsigned & color = * colorPointer ;
2018-11-08 20:56:06 +00:00
int shift = colorAlpha ? 0 : 8 ;
2017-07-10 18:47:38 +00:00
if ( uni > = ' A ' & & uni < = ' D ' ) {
2020-11-19 17:20:06 +00:00
int x = ( slider_x - ( dcenter - dwidth / 4 ) ) * 510 / dwidth ;
2017-07-10 18:47:38 +00:00
if ( x < 0 ) x = 0 ;
if ( x > 255 ) x = 255 ;
2018-11-08 20:56:06 +00:00
part ( color , uni - ' A ' ) = x ;
2017-07-10 18:47:38 +00:00
}
2018-02-03 19:04:33 +00:00
else if ( uni = = ' ' | | uni = = ' \n ' | | uni = = ' \r ' ) {
2017-07-10 18:47:38 +00:00
bool inHistory = false ;
2018-11-08 20:56:06 +00:00
for ( int i = 0 ; i < 10 ; i + + ) if ( colorhistory [ i ] = = ( color < < shift ) )
2017-07-10 18:47:38 +00:00
inHistory = true ;
2018-11-08 20:56:06 +00:00
if ( ! inHistory ) { colorhistory [ lch ] = ( color < < shift ) ; lch + + ; lch % = 10 ; }
2023-08-09 12:01:24 +00:00
if ( ne . reaction ) ne . reaction ( ) ;
ne . popfinal ( ) ;
2017-07-10 18:47:38 +00:00
}
else if ( uni > = ' 0 ' & & uni < = ' 9 ' ) {
2018-11-08 20:56:06 +00:00
color = colorhistory [ uni - ' 0 ' ] > > shift ;
2017-07-10 18:47:38 +00:00
}
else if ( palette & & uni > = ' a ' & & uni < ' a ' + ( int ) palette [ 0 ] ) {
2018-11-08 20:56:06 +00:00
color = palette [ 1 + uni - ' a ' ] > > shift ;
2017-07-10 18:47:38 +00:00
}
2018-12-06 11:31:51 +00:00
else if ( DKEY = = SDLK_DOWN ) {
2017-07-10 18:47:38 +00:00
colorp = ( colorp - 1 ) & 3 ;
}
2018-12-06 11:31:51 +00:00
else if ( DKEY = = SDLK_UP ) {
2017-07-10 18:47:38 +00:00
colorp = ( colorp + 1 ) & 3 ;
}
2018-12-06 11:31:51 +00:00
else if ( DKEY = = SDLK_LEFT ) {
2017-07-10 18:47:38 +00:00
unsigned char * pts = ( unsigned char * ) & color ;
pts [ colorp ] - = abs ( shiftmul ) < .6 ? 1 : 17 ;
}
2018-12-06 11:31:51 +00:00
else if ( DKEY = = SDLK_RIGHT ) {
2017-07-10 18:47:38 +00:00
unsigned char * pts = ( unsigned char * ) & color ;
pts [ colorp ] + = abs ( shiftmul ) < .6 ? 1 : 17 ;
}
2023-08-09 12:01:24 +00:00
else if ( doexiton ( sym , uni ) ) ne . popfinal ( ) ;
2017-07-10 18:47:38 +00:00
}
2019-08-09 19:00:52 +00:00
EX bool colorAlpha ;
2018-11-08 20:56:06 +00:00
2023-08-09 12:01:24 +00:00
void color_dialog : : draw ( ) {
2017-12-03 10:48:02 +00:00
cmode = sm : : NUMBER | dialogflags ;
2022-07-05 09:51:06 +00:00
if ( cmode & sm : : SIDE ) gamescreen ( ) ;
2021-02-07 17:32:39 +00:00
else emptyscreen ( ) ;
2017-12-03 10:48:02 +00:00
dcenter = vid . xres / 2 ;
dwidth = vid . xres ;
2018-11-17 18:24:02 +00:00
if ( current_display - > sidescreen ) {
2017-12-03 10:48:02 +00:00
dwidth = vid . xres - vid . yres ;
dcenter = vid . xres - dwidth / 2 ;
}
2018-09-04 17:53:42 +00:00
color_t color = * colorPointer ;
2017-07-10 18:47:38 +00:00
2017-03-23 10:53:57 +00:00
int ash = 8 ;
for ( int j = 0 ; j < 10 ; j + + ) {
2017-12-03 10:48:02 +00:00
int x = dcenter + vid . fsize * 2 * ( j - 5 ) ;
2017-03-23 10:53:57 +00:00
int y = vid . yres / 2 - 5 * vid . fsize ;
string s0 = " " ; s0 + = ( ' 0 ' + j ) ;
vid . fsize * = 2 ;
displayColorButton ( x , y , s0 , ' 0 ' + j , 0 , 0 , colorhistory [ j ] > > ash ) ;
vid . fsize / = 2 ;
}
if ( palette ) {
int q = palette [ 0 ] ;
for ( int i = 0 ; i < q ; i + + ) {
2017-12-03 10:48:02 +00:00
int x = dcenter + vid . fsize * ( 2 * i - q ) ;
2017-03-23 10:53:57 +00:00
int y = vid . yres / 2 - 7 * vid . fsize ;
string s0 = " " ; s0 + = ( ' a ' + i ) ;
vid . fsize * = 2 ;
displayColorButton ( x , y , s0 , ' a ' + i , 0 , 0 , palette [ i + 1 ] > > ash ) ;
vid . fsize / = 2 ;
}
}
2022-12-04 14:24:42 +00:00
item it ( diSlider ) ;
2022-07-05 10:34:31 +00:00
2017-03-23 10:53:57 +00:00
for ( int i = 0 ; i < 4 ; i + + ) {
int y = vid . yres / 2 + ( 2 - i ) * vid . fsize * 2 ;
2018-11-08 20:56:06 +00:00
if ( i = = 3 & & ! colorAlpha ) continue ;
2022-07-05 10:34:31 +00:00
int in = 3 - i - ( colorAlpha ? 0 : 1 ) ;
2017-03-23 10:53:57 +00:00
2022-07-05 10:34:31 +00:00
color_t colors [ 4 ] = { 0xFF0000 , 0x00FF00 , 0x0000FF , 0xFFFFFF } ;
it . color = colors [ in ] ;
it . param = part ( color , i ) / 255. ;
draw_slider ( dcenter - dwidth / 4 , dcenter + dwidth / 4 , y , it ) ;
2022-12-04 14:24:42 +00:00
color_t col = ( ( i = = colorp ) & & ! mousing ) ? dialogcolor_selected : dialogcolor ;
2022-07-05 10:34:31 +00:00
string rgt ; rgt + = " RGBA " [ in ] ;
displayColorButton ( dcenter + dwidth / 4 + vid . fsize , y , rgt , 0 , 0 , 0 , col ) ;
2017-03-23 10:53:57 +00:00
if ( mousey > = y - vid . fsize & & mousey < y + vid . fsize )
2020-11-19 17:20:06 +00:00
getcstat = ' A ' + i , inslider = true , slider_x = mousex ;
2017-03-23 10:53:57 +00:00
}
2023-08-21 17:02:25 +00:00
displayColorButton ( dcenter , vid . yres / 2 + vid . fsize * 6 , XLAT ( " select this color " ) + " : " + hr : : format ( colorAlpha ? " %08X " : " %06X " , color ) , ' ' , 8 , 0 , color > > ( colorAlpha ? ash : 0 ) ) ;
2018-08-01 01:59:20 +00:00
if ( extra_options ) extra_options ( ) ;
2017-07-10 18:47:38 +00:00
2023-08-09 12:01:24 +00:00
keyhandler = [ this ] ( int sym , int uni ) { return handleKeyColor ( sym , uni , self ) ; } ;
2017-03-23 10:53:57 +00:00
}
2019-08-09 19:00:52 +00:00
EX void openColorDialog ( unsigned int & col , unsigned int * pal IS ( palette ) ) {
2023-08-09 12:01:24 +00:00
color_dialog cd ;
2017-03-23 10:53:57 +00:00
colorPointer = & col ; palette = pal ;
2018-11-08 20:56:06 +00:00
colorAlpha = true ;
2023-08-09 12:01:24 +00:00
pushScreen ( cd ) ;
2017-03-23 10:53:57 +00:00
}
2023-08-09 12:01:24 +00:00
# if HDR
struct matrix_dialog : extdialog {
2023-08-10 12:38:59 +00:00
transmatrix * edit_matrix ;
int dim ;
2023-08-09 12:01:24 +00:00
void draw ( ) override ;
2023-08-14 02:36:39 +00:00
void large_viz ( ) ;
2023-08-09 12:01:24 +00:00
} ;
# endif
2023-08-14 02:36:39 +00:00
void matrix_dialog : : large_viz ( ) {
2023-08-09 12:01:24 +00:00
addCustom ( 500 , [ this ] {
int siz = dfsize * 5 ;
int mid = ( top + tothei ) / 2 ;
2023-08-15 15:25:00 +00:00
vid . linewidth * = 3 ;
visualize_matrix ( * edit_matrix , dcenter , mid , siz / 2 , dim , vid . fsize * 2 ) ;
vid . linewidth / = 3 ;
2023-08-09 12:01:24 +00:00
} ) ;
2023-08-14 02:36:39 +00:00
}
void matrix_dialog : : draw ( ) {
cmode = dialogflags ;
gamescreen ( ) ;
init ( title ) ;
2023-08-15 13:39:00 +00:00
addHelp ( help ) ;
2023-08-14 02:36:39 +00:00
large_viz ( ) ;
2023-08-09 12:01:24 +00:00
addBreak ( 100 ) ;
2023-08-14 02:36:39 +00:00
addItem ( " reset " , ' r ' ) ;
dialog : : add_action ( [ this ] { * edit_matrix = Id ; } ) ;
if ( dim = = 2 ) {
static ld angle ;
angle = as_degrees ( * edit_matrix ) ;
2023-08-14 15:44:22 +00:00
addSelItem ( " enter angle " , fts ( angle ) + " ° " , ' a ' ) ;
2023-08-14 02:36:39 +00:00
dialog : : add_action ( [ this ] {
editNumber ( angle , - 180 , 180 , 90 , 0 , title , help ) ;
auto & ne = get_ne ( ) ;
auto re = reaction ;
ne . extra_options = [ this ] { large_viz ( ) ; } ;
ne . reaction = [ re , this ] { * edit_matrix = spin ( angle * degree ) ; if ( re ) re ( ) ; } ;
ne . reaction_final = reaction ;
ne . animatable = false ;
2023-08-14 15:42:15 +00:00
ne . dialogflags | = dialogflags ;
2023-08-14 02:36:39 +00:00
} ) ;
}
if ( dim = = 3 ) {
transmatrix cur = * edit_matrix ;
auto rot_but = [ this , cur ] ( int i , int j , string title , char key ) {
addItem ( title , key ) ;
dialog : : add_action ( [ i , j , title , this , cur ] {
static ld angle ; angle = 0 ;
editNumber ( angle , - 180 , 180 , 90 , 0 , title , XLAT ( " Angle to rotate by. " ) ) ;
auto & ne = get_ne ( ) ;
auto re = reaction ;
ne . extra_options = [ this ] { large_viz ( ) ; } ;
ne . reaction = [ re , i , j , this , cur ] { * edit_matrix = cspin ( i , j , angle * degree ) * cur ; if ( re ) re ( ) ; } ;
ne . reaction_final = reaction ;
ne . animatable = false ;
2023-08-14 15:42:15 +00:00
ne . dialogflags | = dialogflags ;
2023-08-14 02:36:39 +00:00
} ) ;
} ;
2023-08-15 15:08:41 +00:00
rot_but ( 0 , 2 , " rotate in XZ " , ' x ' ) ;
rot_but ( 1 , 2 , " rotate in YZ " , ' y ' ) ;
2023-08-14 02:36:39 +00:00
rot_but ( 0 , 1 , " rotate in XY " , ' z ' ) ;
}
2023-08-14 02:50:13 +00:00
2023-12-30 07:10:34 +00:00
# if !ISMOBILE
2023-08-14 02:50:13 +00:00
addBoolItem ( " mouse control " , dialogflags & sm : : MOUSEAIM , ' m ' ) ;
dialog : : add_action ( [ this ] { dialogflags ^ = sm : : MOUSEAIM ; } ) ;
if ( dialogflags & sm : : MOUSEAIM ) {
* edit_matrix = cspin ( 0 , 2 , mouseaim_x ) * * edit_matrix ;
* edit_matrix = cspin ( 1 , 2 , mouseaim_y ) * * edit_matrix ;
mouseaim_x = mouseaim_y = 0 ;
}
2023-12-30 07:10:34 +00:00
# endif
2023-08-14 02:50:13 +00:00
2023-08-14 02:36:39 +00:00
static string formula ;
formula = " ? " ;
anims : : get_parameter_animation ( anims : : find_param ( edit_matrix ) , formula ) ;
addSelItem ( " enter formula " , formula , ' f ' ) ;
2023-08-09 12:01:24 +00:00
dialog : : add_action ( [ this ] {
2023-08-14 02:36:39 +00:00
if ( formula = = " ? " ) formula = " id " ;
anims : : get_parameter_animation ( anims : : find_param ( edit_matrix ) , formula ) ;
dialog : : edit_string ( formula , " formula " , XLAT ( " dxy(n) = rotate n degrees from x to y \n \n d-degree, r-radian, t-turn \n \n example: dxy(30)*dyz(45) " ) ) ;
dialog : : get_di ( ) . extra_options = [ this ] { large_viz ( ) ; } ;
dialog : : get_di ( ) . reaction = [ this ] {
try {
* edit_matrix = parsematrix ( formula ) ;
auto p = anims : : find_param ( edit_matrix ) ;
if ( p ) p - > load_as_animation ( formula ) ;
}
catch ( hr_parse_exception & ) { }
2024-05-27 00:18:22 +00:00
catch ( param_exception & ) { }
2023-08-14 02:36:39 +00:00
} ;
2023-08-14 15:42:15 +00:00
dialog : : get_di ( ) . dialogflags | = dialogflags ;
2023-08-09 12:01:24 +00:00
} ) ;
2023-08-14 14:59:46 +00:00
if ( extra_options ) extra_options ( ) ;
2023-08-09 12:01:24 +00:00
addBack ( ) ;
display ( ) ;
}
2023-08-10 12:38:59 +00:00
EX void editMatrix ( transmatrix & T , string t , string h , int dim ) {
2023-08-09 12:01:24 +00:00
matrix_dialog m ;
m . edit_matrix = & T ;
m . title = t ;
m . help = h ;
2023-08-10 12:38:59 +00:00
m . dim = dim ;
2023-08-09 12:01:24 +00:00
pushScreen ( m ) ;
}
2019-08-09 19:00:52 +00:00
EX bool editingDetail ( ) {
2023-08-14 02:37:01 +00:00
auto ptr = dynamic_cast < number_dialog * > ( screens . back ( ) . target_base ( ) ) ;
if ( ! ptr ) return false ;
2023-08-09 12:01:24 +00:00
auto & ne = get_ne ( ) ;
2019-05-29 14:27:24 +00:00
return ne . editwhat = = & vid . highdetail | | ne . editwhat = = & vid . middetail ;
2017-03-23 10:53:57 +00:00
}
2017-11-06 20:18:12 +00:00
int ldtoint ( ld x ) {
if ( x > 0 ) return int ( x + .5 ) ;
else return int ( x - .5 ) ;
}
2023-08-09 12:22:32 +00:00
string number_dialog : : disp ( ld x ) {
if ( dialogflags & sm : : HEXEDIT ) return " 0x " + itsh ( ( unsigned long long ) ( x ) ) ;
if ( intval ) return its ( ldtoint ( x ) ) ;
2023-08-09 12:01:24 +00:00
return fts ( x ) ;
}
2017-03-23 10:53:57 +00:00
2023-08-09 12:01:24 +00:00
void number_dialog : : apply_slider ( ) {
auto & ne = self ;
2018-11-09 19:41:55 +00:00
if ( ne . intval ) * ne . intval = ldtoint ( * ne . editwhat ) ;
2023-08-09 12:01:24 +00:00
if ( ne . reaction ) ne . reaction ( ) ;
2018-11-09 19:41:55 +00:00
if ( ne . intval ) * ne . editwhat = * ne . intval ;
2023-08-09 12:22:32 +00:00
reset_str ( ) ;
2019-02-17 17:43:39 +00:00
# if CAP_ANIMATIONS
2023-08-08 23:01:32 +00:00
anims : : deanimate ( anims : : find_param ( ne . editwhat ) ) ;
2019-02-17 17:43:39 +00:00
# endif
2018-11-09 19:41:55 +00:00
}
2019-08-09 19:00:52 +00:00
EX void use_hexeditor ( ) {
2023-08-09 12:01:24 +00:00
auto & ne = get_ne ( ) ;
ne . dialogflags | = sm : : HEXEDIT ;
2023-08-09 12:22:32 +00:00
ne . reset_str ( ) ;
2019-01-18 20:04:29 +00:00
}
2023-08-09 12:01:24 +00:00
void number_dialog : : apply_edit ( ) {
auto & ne = self ;
2019-12-23 20:44:51 +00:00
try {
exp_parser ep ;
ep . s = ne . s ;
ld x = ep . rparse ( ) ;
if ( ne . sc . positive & & x < = 0 ) return ;
* ne . editwhat = x ;
if ( ne . intval ) * ne . intval = ldtoint ( * ne . editwhat ) ;
# if CAP_ANIMATIONS
2023-08-08 23:01:32 +00:00
if ( ne . animatable ) {
2023-08-08 23:11:44 +00:00
auto p = anims : : find_param ( ne . intval ? ( void * ) ne . intval : ( void * ) ne . editwhat ) ;
2023-08-08 23:01:32 +00:00
if ( p ) p - > load_as_animation ( ne . s ) ;
}
2019-12-23 20:44:51 +00:00
# endif
if ( reaction ) reaction ( ) ;
}
2021-03-21 21:56:38 +00:00
catch ( const hr_parse_exception & ) {
2019-12-23 20:44:51 +00:00
}
2024-05-27 00:18:22 +00:00
catch ( param_exception & ) { }
2018-11-09 19:41:55 +00:00
}
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX void bound_low ( ld val ) {
2023-08-09 12:01:24 +00:00
auto & ne = get_ne ( ) ;
auto r = ne . reaction ;
ne . reaction = [ r , val , & ne ] ( ) {
2018-11-09 19:41:55 +00:00
if ( * ne . editwhat < val ) {
* ne . editwhat = val ;
if ( ne . intval ) * ne . intval = ldtoint ( * ne . editwhat ) ;
}
if ( r ) r ( ) ;
} ;
}
2017-03-23 10:53:57 +00:00
2019-08-09 19:00:52 +00:00
EX void bound_up ( ld val ) {
2023-08-09 12:01:24 +00:00
auto & ne = get_ne ( ) ;
auto r = ne . reaction ;
ne . reaction = [ r , val , & ne ] ( ) {
2018-11-09 19:41:55 +00:00
if ( * ne . editwhat > val ) {
* ne . editwhat = val ;
if ( ne . intval ) * ne . intval = ldtoint ( * ne . editwhat ) ;
}
if ( r ) r ( ) ;
} ;
2017-03-23 10:53:57 +00:00
}
2018-11-09 19:41:55 +00:00
2019-08-09 19:00:52 +00:00
EX void formula_keyboard ( bool lr ) {
2019-07-03 05:31:09 +00:00
addKeyboardItem ( " 1234567890 " ) ;
2019-07-03 06:06:42 +00:00
addKeyboardItem ( " =+-*/^() \ x3 " ) ;
2019-07-03 05:31:09 +00:00
addKeyboardItem ( " qwertyuiop " ) ;
addKeyboardItem ( " asdfghjkl " ) ;
addKeyboardItem ( " zxcvbnm,. \b " ) ;
addKeyboardItem ( lr ? " \t \ x1 \ x2 " : " \t " ) ;
}
2021-02-01 12:42:12 +00:00
EX bool onscreen_keyboard = ISMOBILE ;
2023-08-09 12:01:24 +00:00
struct number_dialog_help {
number_dialog * ptr ;
void operator ( ) ( ) ;
} ;
void number_dialog_help : : operator ( ) ( ) {
auto ne = * ptr ;
2021-02-01 12:42:12 +00:00
init ( " number dialog help " ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addHelp ( XLAT ( " You can enter formulas in this dialog. " ) ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addHelp ( XLAT ( " Functions available: " ) ) ;
addHelp ( available_functions ( ) ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addHelp ( XLAT ( " Constants and variables available: " ) ) ;
addHelp ( available_constants ( ) ) ;
2023-08-09 12:01:24 +00:00
if ( ptr & & ne . animatable ) {
2021-02-01 12:42:12 +00:00
dialog : : addBreak ( 100 ) ;
dialog : : addHelp ( XLAT ( " Animations: " ) ) ;
dialog : : addHelp ( XLAT ( " a..b -- animate linearly from a to b " ) ) ;
dialog : : addHelp ( XLAT ( " a..b..|c..d -- animate from a to b, then from c to d " ) ) ;
dialog : : addHelp ( XLAT ( " a../x..b../y -- change smoothly, x and y are derivatives " ) ) ;
}
/* "Most parameters can be animated simply by using '..' in their editing dialog. "
" For example, the value of a parameter set to 0..1 will grow linearly from 0 to 1. "
" You can also use functions (e.g. cos(0..2*pi)) and refer to other parameters. "
) ) ; */
# if CAP_ANIMATIONS
dialog : : addBreak ( 50 ) ;
2023-08-09 12:01:24 +00:00
auto f = find_edit ( ! ptr ? nullptr : ne . intval ? ( void * ) ne . intval : ( void * ) ne . editwhat ) ;
2021-02-01 12:42:12 +00:00
if ( f )
2024-05-26 18:22:29 +00:00
dialog : : addHelp ( XLAT ( " Parameter names, e.g. '%1' " , f - > name ) ) ;
2021-02-01 12:42:12 +00:00
else
dialog : : addHelp ( XLAT ( " Parameter names " ) ) ;
dialog : : addBreak ( 50 ) ;
for ( auto & ap : anims : : aps ) {
2024-05-26 18:22:29 +00:00
dialog : : addInfo ( ap . par - > name + " = " + ap . formula ) ;
2021-02-01 12:42:12 +00:00
}
# endif
dialog : : addBreak ( 50 ) ;
dialog : : addHelp ( XLAT ( " These can be combined, e.g. %1 " , " projection*sin(0..2*pi) " ) ) ;
display ( ) ;
}
EX void parser_help ( ) {
2023-08-09 12:01:24 +00:00
number_dialog_help ndh ;
ndh . ptr = nullptr ;
2021-02-01 12:42:12 +00:00
addItem ( " help " , SDLK_F1 ) ;
2023-08-09 12:01:24 +00:00
add_action_push ( ndh ) ;
2021-02-01 12:42:12 +00:00
}
2023-08-09 12:01:24 +00:00
void number_dialog : : draw ( ) {
2017-07-12 17:50:39 +00:00
cmode = sm : : NUMBER | dialogflags ;
2022-07-05 09:51:06 +00:00
gamescreen ( ) ;
2023-08-09 12:01:24 +00:00
init ( title ) ;
addInfo ( s ) ;
auto & ne = self ;
2019-05-21 22:03:51 +00:00
if ( ne . intval & & ne . sc . direct = = & identity_f )
addIntSlider ( int ( ne . vmin ) , int ( * ne . editwhat ) , int ( ne . vmax ) , 500 ) ;
else
addSlider ( ne . sc . direct ( ne . vmin ) , ne . sc . direct ( * ne . editwhat ) , ne . sc . direct ( ne . vmax ) , 500 ) ;
2017-03-23 10:53:57 +00:00
addBreak ( 100 ) ;
2020-05-03 18:56:41 +00:00
# if !ISMOBILE
2018-02-13 12:37:20 +00:00
addHelp ( XLAT ( " You can scroll with arrow keys -- Ctrl to fine-tune " ) ) ;
2017-03-23 10:53:57 +00:00
addBreak ( 100 ) ;
# endif
2018-06-12 22:00:01 +00:00
dialog : : addBack ( ) ;
2018-02-13 12:37:20 +00:00
addSelItem ( XLAT ( " default value " ) , disp ( ne . dft ) , SDLK_HOME ) ;
2021-02-01 12:42:12 +00:00
add_edit ( onscreen_keyboard ) ;
addItem ( " help " , SDLK_F1 ) ;
2023-08-09 12:01:24 +00:00
add_action ( [ this ] { number_dialog_help ndh ; ndh . ptr = this ; pushScreen ( ndh ) ; } ) ;
2017-03-23 10:53:57 +00:00
addBreak ( 100 ) ;
if ( ne . help ! = " " ) {
addHelp ( ne . help ) ;
2018-06-22 12:47:24 +00:00
// bool scal = !ISMOBILE && !ISPANDORA && isize(ne.help) > 160;
2017-10-08 22:21:39 +00:00
// if(scal) lastItem().scale = 30;
2017-03-23 10:53:57 +00:00
}
2018-08-01 01:59:20 +00:00
if ( extra_options ) extra_options ( ) ;
2018-04-23 10:34:14 +00:00
2021-02-01 12:42:12 +00:00
if ( onscreen_keyboard ) {
addBreak ( 100 ) ;
formula_keyboard ( false ) ;
}
2019-07-03 05:31:09 +00:00
2017-03-23 10:53:57 +00:00
display ( ) ;
2024-06-28 10:20:26 +00:00
# if CAP_SDL2
texthandler = [ & ne ] ( const SDL_TextInputEvent & ev ) {
if ( key_actions . count ( ev . text [ 0 ] ) ) return ;
ne . s + = ev . text ;
ne . apply_edit ( ) ;
} ;
# endif
2017-07-10 18:47:38 +00:00
2023-08-09 12:01:24 +00:00
keyhandler = [ this , & ne ] ( int sym , int uni ) {
2017-07-10 18:47:38 +00:00
handleNavigation ( sym , uni ) ;
2021-02-01 12:42:12 +00:00
if ( ( uni > = ' 0 ' & & uni < = ' 9 ' ) | | among ( uni , ' . ' , ' + ' , ' - ' , ' * ' , ' / ' , ' ^ ' , ' ( ' , ' ) ' , ' , ' , ' | ' , 3 ) | | ( uni > = ' a ' & & uni < = ' z ' ) ) {
2024-06-28 10:20:26 +00:00
# if !CAP_SDL2
2019-07-03 05:31:09 +00:00
if ( uni = = 3 ) ne . s + = " pi " ;
else ne . s + = uni ;
2018-11-09 19:41:55 +00:00
apply_edit ( ) ;
2024-06-28 10:20:26 +00:00
# endif
2017-07-10 18:47:38 +00:00
}
else if ( uni = = ' \b ' | | uni = = ' \t ' ) {
2024-06-28 10:20:26 +00:00
ne . s = ne . s . substr ( 0 , isize ( ne . s ) - utfsize_before ( ne . s , isize ( ne . s ) ) ) ;
2017-07-10 18:47:38 +00:00
sscanf ( ne . s . c_str ( ) , LDF , ne . editwhat ) ;
2018-11-09 19:41:55 +00:00
apply_edit ( ) ;
2017-07-10 18:47:38 +00:00
}
2017-07-22 23:33:27 +00:00
# if !ISMOBILE
2018-12-06 11:31:51 +00:00
else if ( DKEY = = SDLK_RIGHT ) {
2017-07-10 18:47:38 +00:00
if ( ne . intval & & abs ( shiftmul ) < .6 )
( * ne . editwhat ) + + ;
else
2018-09-10 14:47:28 +00:00
* ne . editwhat = ne . sc . inverse ( ne . sc . direct ( * ne . editwhat ) + shiftmul * ne . step ) ;
2019-05-21 22:03:51 +00:00
if ( abs ( * ne . editwhat ) < ne . step * 1e-6 & & ! ne . intval ) * ne . editwhat = 0 ;
2018-11-09 19:41:55 +00:00
apply_slider ( ) ;
2017-07-10 18:47:38 +00:00
}
2018-12-06 11:31:51 +00:00
else if ( DKEY = = SDLK_LEFT ) {
2017-07-10 18:47:38 +00:00
if ( ne . intval & & abs ( shiftmul ) < .6 )
( * ne . editwhat ) - - ;
else
2018-09-10 14:47:28 +00:00
* ne . editwhat = ne . sc . inverse ( ne . sc . direct ( * ne . editwhat ) - shiftmul * ne . step ) ;
2019-05-21 22:03:51 +00:00
if ( abs ( * ne . editwhat ) < ne . step * 1e-6 & & ! ne . intval ) * ne . editwhat = 0 ;
2018-11-09 19:41:55 +00:00
apply_slider ( ) ;
2017-07-10 18:47:38 +00:00
}
# endif
else if ( sym = = SDLK_HOME ) {
* ne . editwhat = ne . dft ;
2018-11-09 19:41:55 +00:00
apply_slider ( ) ;
2017-07-10 18:47:38 +00:00
}
else if ( uni = = 500 ) {
int sl , sr ;
2018-11-17 18:24:02 +00:00
if ( current_display - > sidescreen )
2017-07-10 18:47:38 +00:00
sl = vid . yres + vid . fsize * 2 , sr = vid . xres - vid . fsize * 2 ;
else
sl = vid . xres / 4 , sr = vid . xres * 3 / 4 ;
2020-11-19 17:20:06 +00:00
ld d = ( slider_x - sl + .0 ) / ( sr - sl ) ;
2019-05-21 22:03:51 +00:00
ld val = ne . sc . inverse ( d * ( ne . sc . direct ( ne . vmax ) - ne . sc . direct ( ne . vmin ) ) + ne . sc . direct ( ne . vmin ) ) ;
ld nextval = ne . sc . inverse ( ( mousex + 1. - sl ) / ( sr - sl ) * ( ne . sc . direct ( ne . vmax ) - ne . sc . direct ( ne . vmin ) ) + ne . sc . direct ( ne . vmin ) ) ;
ld dif = abs ( val - nextval ) ;
if ( dif > 1e-6 ) {
ld mul = 1 ;
while ( dif < 10 ) dif * = 10 , mul * = 10 ;
val * = mul ;
val = floor ( val + 0.5 ) ;
val / = mul ;
}
* ne . editwhat = val ;
2018-11-09 19:41:55 +00:00
apply_slider ( ) ;
2017-07-10 18:47:38 +00:00
}
2023-08-09 12:01:24 +00:00
else if ( doexiton ( sym , uni ) ) ne . popfinal ( ) ;
2017-07-10 18:47:38 +00:00
} ;
2024-05-27 13:21:31 +00:00
}
void bool_dialog : : draw ( ) {
cmode = dialogflags ;
gamescreen ( ) ;
init ( title ) ;
dialog : : addBreak ( 100 ) ;
auto switch_to = [ this ] ( bool b ) {
bool do_switch = ( * editwhat ! = b ) ;
auto sw = switcher ;
auto re = reaction ;
popScreen ( ) ;
if ( do_switch ) { sw ( ) ; if ( re ) re ( ) ; }
} ;
dialog : : addBoolItem ( XLAT ( " disable " ) , false , ' 0 ' ) ;
dialog : : add_action ( [ switch_to ] { switch_to ( false ) ; } ) ;
dialog : : addBoolItem ( XLAT ( " enable " ) , true , ' 1 ' ) ;
dialog : : add_action ( [ switch_to ] { switch_to ( true ) ; } ) ;
dialog : : addBoolItem ( XLAT ( " switch " ) , ! * editwhat , ' s ' ) ;
dialog : : add_action ( [ switch_to , this ] { switch_to ( ! * editwhat ) ; } ) ;
dialog : : addBoolItem ( XLAT ( " set default " ) , dft , ' d ' ) ;
dialog : : add_action ( [ switch_to , this ] { switch_to ( dft ) ; } ) ;
dialog : : addBreak ( 100 ) ;
if ( help ! = " " ) addHelp ( help ) ;
if ( extra_options ) extra_options ( ) ;
display ( ) ;
}
2017-03-23 10:53:57 +00:00
int nlpage = 1 ;
int wheelshift = 0 ;
2019-08-09 19:00:52 +00:00
EX int handlePage ( int & nl , int & nlm , int perpage ) {
2017-03-23 10:53:57 +00:00
nlm = nl ;
int onl = nl ;
int ret = 0 ;
if ( nlpage ) {
nl = nlm = perpage ;
if ( nlpage = = 2 ) ret = nlm ;
int w = wheelshift ;
int realw = 0 ;
while ( w < 0 & & ret ) {
ret - - ; w + + ; realw - - ;
}
while ( w > 0 & & ret + perpage < onl ) {
ret + + ; w - - ; realw + + ;
}
wheelshift = realw ;
if ( ret + nl > onl ) nl = onl - ret ;
}
return ret ;
}
2019-08-09 19:00:52 +00:00
EX void displayPageButtons ( int i , bool pages ) {
2017-03-23 10:53:57 +00:00
int i0 = vid . yres - vid . fsize ;
int xr = vid . xres / 80 ;
2018-09-05 13:18:40 +00:00
if ( pages ) if ( displayfrZH ( xr * 8 , i0 , 1 , vid . fsize , IFM ( " 1 - " ) + XLAT ( " page " ) + " 1 " , nlpage = = 1 ? 0xD8D8C0 : dialogcolor , 8 ) )
2017-03-23 10:53:57 +00:00
getcstat = ' 1 ' ;
2018-09-05 13:18:40 +00:00
if ( pages ) if ( displayfrZH ( xr * 24 , i0 , 1 , vid . fsize , IFM ( " 2 - " ) + XLAT ( " page " ) + " 2 " , nlpage = = 1 ? 0xD8D8C0 : dialogcolor , 8 ) )
2017-03-23 10:53:57 +00:00
getcstat = ' 2 ' ;
2018-09-05 13:18:40 +00:00
if ( pages ) if ( displayfrZH ( xr * 40 , i0 , 1 , vid . fsize , IFM ( " 3 - " ) + XLAT ( " all " ) , nlpage = = 1 ? 0xD8D8C0 : dialogcolor , 8 ) )
2017-03-23 10:53:57 +00:00
getcstat = ' 3 ' ;
2018-09-05 13:18:40 +00:00
if ( i & 1 ) if ( displayfrZH ( xr * 56 , i0 , 1 , vid . fsize , IFM ( keyname ( SDLK_ESCAPE ) + " - " ) + XLAT ( " go back " ) , dialogcolor , 8 ) )
2017-03-23 10:53:57 +00:00
getcstat = ' 0 ' ;
2018-09-05 13:18:40 +00:00
if ( i & 2 ) if ( displayfrZH ( xr * 72 , i0 , 1 , vid . fsize , IFM ( " F1 - " ) + XLAT ( " help " ) , dialogcolor , 8 ) )
2017-03-23 10:53:57 +00:00
getcstat = SDLK_F1 ;
2021-05-30 11:21:22 +00:00
if ( i & 4 ) if ( displayfrZH ( xr * 8 , i0 , 1 , vid . fsize , IFM ( " 1 - " ) + XLAT ( " plain " ) , dialogcolor , 8 ) )
getcstat = ' 1 ' ;
2017-03-23 10:53:57 +00:00
}
2019-08-09 19:00:52 +00:00
EX bool handlePageButtons ( int uni ) {
2017-03-23 10:53:57 +00:00
if ( uni = = ' 1 ' ) nlpage = 1 , wheelshift = 0 ;
else if ( uni = = ' 2 ' ) nlpage = 2 , wheelshift = 0 ;
else if ( uni = = ' 3 ' ) nlpage = 0 , wheelshift = 0 ;
else if ( uni = = PSEUDOKEY_WHEELUP ) wheelshift - - ;
else if ( uni = = PSEUDOKEY_WHEELDOWN ) wheelshift + + ;
else return false ;
return true ;
}
2023-08-09 12:01:24 +00:00
extdialog : : extdialog ( ) {
dialogflags = 0 ;
if ( cmode & sm : : SIDE ) dialogflags | = sm : : MAYDARK | sm : : SIDE ;
reaction = reaction_t ( ) ;
reaction_final = reaction_t ( ) ;
extra_options = reaction_t ( ) ;
}
2023-08-15 08:54:36 +00:00
EX number_dialog & editNumber ( ld & x , ld vmin , ld vmax , ld step , ld dft , string title , string help ) {
2023-08-09 12:01:24 +00:00
number_dialog ne ;
2017-07-10 18:47:38 +00:00
ne . editwhat = & x ;
ne . vmin = vmin ;
ne . vmax = vmax ;
ne . step = step ;
ne . dft = dft ;
ne . title = title ;
ne . help = help ;
2018-09-10 14:47:28 +00:00
ne . sc = identity ;
2017-07-10 18:47:38 +00:00
ne . intval = NULL ;
2018-11-09 19:41:55 +00:00
ne . animatable = true ;
2019-02-17 17:43:39 +00:00
# if CAP_ANIMATIONS
2023-08-08 23:01:32 +00:00
anims : : get_parameter_animation ( anims : : find_param ( & x ) , ne . s ) ;
2019-02-17 17:43:39 +00:00
# endif
2023-08-09 12:22:32 +00:00
ne . reset_str ( ) ;
2023-08-09 12:01:24 +00:00
pushScreen ( ne ) ;
2023-08-15 08:54:36 +00:00
return get_ne ( ) ;
2023-08-08 15:20:39 +00:00
}
2024-05-27 13:21:31 +00:00
EX extdialog & editBool ( bool & b , bool dft , string title , string help , const reaction_t & switcher ) {
bool_dialog be ;
be . editwhat = & b ;
be . dft = dft ;
be . title = title ;
be . help = help ;
be . switcher = switcher ;
pushScreen ( be ) ;
return get_di ( ) ;
}
2023-08-15 08:54:36 +00:00
EX number_dialog & editNumber ( int & x , int vmin , int vmax , ld step , int dft , string title , string help ) {
2023-08-09 12:01:24 +00:00
ld tmp ;
2023-08-15 08:54:36 +00:00
auto & ne = editNumber ( tmp , vmin , vmax , step , dft , title , help ) ;
2023-08-09 12:01:24 +00:00
ne . editwhat = & ne . intbuf ; ne . intbuf = x ; ne . intval = & x ; ne . s = its ( x ) ;
anims : : get_parameter_animation ( anims : : find_param ( & x ) , ne . s ) ;
2023-08-15 08:54:36 +00:00
return ne ;
2017-07-10 18:47:38 +00:00
}
2019-08-09 19:00:52 +00:00
EX void helpToEdit ( int & x , int vmin , int vmax , int step , int dft ) {
2017-10-08 22:21:39 +00:00
popScreen ( ) ;
string title = " help " ;
if ( help [ 0 ] = = ' @ ' ) {
int iv = help . find ( " \t " ) ;
int id = help . find ( " \n " ) ;
title = help . substr ( iv + 1 , id - iv - 1 ) ;
help = help . substr ( id + 1 ) ;
}
editNumber ( x , vmin , vmax , step , dft , title , help ) ;
}
2017-12-09 03:01:56 +00:00
//-- choose file dialog--
2018-09-05 13:18:40 +00:00
# define CDIR dialogcolor
2018-02-03 13:31:17 +00:00
# define CFILE forecolor
2018-09-05 13:18:40 +00:00
bool filecmp ( const pair < string , color_t > & f1 , const pair < string , color_t > & f2 ) {
2017-12-09 03:01:56 +00:00
if ( f1 . first = = " ../ " ) return true ;
if ( f2 . first = = " ../ " ) return false ;
if ( f1 . second ! = f2 . second )
return f1 . second = = CDIR ;
return f1 . first < f2 . first ;
}
string filecaption , cfileext ;
string * cfileptr ;
bool editext = false ;
2017-12-14 11:10:40 +00:00
bool_reaction_t file_action ;
2018-06-12 20:12:15 +00:00
void handleKeyFile ( int sym , int uni ) ;
2017-12-09 03:01:56 +00:00
2022-11-03 18:31:28 +00:00
bool search_mode ;
2023-08-09 12:01:24 +00:00
struct file_dialog : extdialog {
void draw ( ) override ;
} ;
void file_dialog : : draw ( ) {
2022-11-03 18:31:06 +00:00
cmode = sm : : NUMBER | dialogflags | sm : : DIALOG_WIDE ;
2022-10-21 09:00:08 +00:00
gamescreen ( ) ;
init ( filecaption ) ;
2017-12-09 03:01:56 +00:00
2022-10-21 09:00:08 +00:00
string cfile = * cfileptr ;
dialog : : addItem ( cfile , 0 ) ;
dialog : : addBreak ( 100 ) ;
2017-12-09 03:01:56 +00:00
v . clear ( ) ;
2022-10-21 09:00:08 +00:00
2017-12-09 03:01:56 +00:00
DIR * d ;
struct dirent * dir ;
2022-10-21 09:00:08 +00:00
2017-12-09 03:01:56 +00:00
string where = " . " ;
2022-11-03 18:31:28 +00:00
string what = cfile ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( cfile ) ; i + + )
2022-11-03 18:31:28 +00:00
if ( cfile [ i ] = = ' / ' | | cfile [ i ] = = ' \\ ' ) {
2017-12-09 03:01:56 +00:00
where = cfile . substr ( 0 , i + 1 ) ;
2022-11-03 18:31:28 +00:00
what = cfile . substr ( i + 1 ) ;
}
2022-10-21 09:00:08 +00:00
2017-12-09 03:01:56 +00:00
d = opendir ( where . c_str ( ) ) ;
if ( d ) {
while ( ( dir = readdir ( d ) ) ! = NULL ) {
string s = dir - > d_name ;
if ( s ! = " .. " & & s [ 0 ] = = ' . ' ) ;
2022-11-03 18:31:28 +00:00
else if ( search_mode ) {
if ( has_substring ( human_simplify ( s , true ) , human_simplify ( what , true ) ) )
v . push_back ( make_pair ( s , CFILE ) ) ;
}
2018-06-22 12:47:24 +00:00
else if ( isize ( s ) > 4 & & s . substr ( isize ( s ) - 4 ) = = cfileext )
2017-12-09 03:01:56 +00:00
v . push_back ( make_pair ( s , CFILE ) ) ;
else if ( dir - > d_type & DT_DIR )
v . push_back ( make_pair ( s + " / " , CDIR ) ) ;
}
closedir ( d ) ;
}
sort ( v . begin ( ) , v . end ( ) , filecmp ) ;
2022-11-03 18:32:12 +00:00
dialog : : start_list ( 2000 , 2000 ) ;
2022-10-21 09:00:08 +00:00
for ( auto & vv : v ) {
dialog : : addItem ( vv . first , list_fake_key + + ) ;
dialog : : lastItem ( ) . color = vv . second ;
string vf = vv . first ;
bool dir = vv . second = = CDIR ;
dialog : : add_action ( [ vf , dir ] {
string & s ( * cfileptr ) ;
string where = " " , what = s , whereparent = " ../ " ;
2022-11-03 18:32:12 +00:00
string last = " " ;
2022-10-21 09:00:08 +00:00
for ( int i = 0 ; i < isize ( s ) ; i + + )
if ( s [ i ] = = ' / ' ) {
2022-11-03 18:32:12 +00:00
if ( i > = 2 & & s . substr ( i - 2 , 3 ) = = " ../ " ) {
2022-10-21 09:00:08 +00:00
whereparent = s . substr ( 0 , i + 1 ) + " ../ " ;
2022-11-03 18:32:12 +00:00
last = " " ;
}
else {
last = s . substr ( isize ( where ) , i + 1 - isize ( where ) ) ;
2022-10-21 09:00:08 +00:00
whereparent = where ;
2022-11-03 18:32:12 +00:00
}
2022-10-21 09:00:08 +00:00
where = s . substr ( 0 , i + 1 ) , what = s . substr ( i + 1 ) ;
}
2022-10-27 10:51:25 +00:00
string str1 ;
2022-11-03 18:32:12 +00:00
if ( vf = = " ../ " ) {
s = whereparent + what ;
find_highlight ( last ) ;
list_skip = 0 ;
}
else if ( dir ) {
s = where + vf + what ;
find_highlight ( " ../ " ) ;
list_skip = 0 ;
}
else {
2022-10-27 10:51:25 +00:00
str1 = where + vf ;
2022-11-03 18:32:12 +00:00
if ( s = = str1 ) {
2023-08-09 12:01:24 +00:00
bool ac = file_action ( ) ;
if ( ac ) popScreen ( ) ;
2022-11-03 18:32:12 +00:00
}
s = str1 ;
2022-10-27 10:51:25 +00:00
}
2022-10-21 09:00:08 +00:00
} ) ;
2017-12-09 03:01:56 +00:00
}
2022-10-21 09:00:08 +00:00
dialog : : end_list ( ) ;
dialog : : addBreak ( 100 ) ;
dialog : : addBoolItem_action ( " extension " , editext , SDLK_F4 ) ;
2022-11-03 18:31:28 +00:00
dialog : : addBoolItem_action ( " search mode " , search_mode , SDLK_F3 ) ;
2022-10-21 09:00:08 +00:00
dialog : : addItem ( " choose " , SDLK_RETURN ) ;
dialog : : addItem ( " cancel " , SDLK_ESCAPE ) ;
dialog : : display ( ) ;
2017-12-09 03:01:56 +00:00
2024-06-28 10:20:26 +00:00
# if CAP_SDL2
texthandler = [ this ] ( const SDL_TextInputEvent & ev ) {
int i = isize ( * cfileptr ) - ( editext ? 0 : 4 ) ;
cfileptr - > insert ( i , ev . text ) ;
} ;
# endif
2017-12-09 03:01:56 +00:00
keyhandler = handleKeyFile ;
}
2019-08-09 19:00:52 +00:00
EX void handleKeyFile ( int sym , int uni ) {
2022-10-21 09:00:08 +00:00
handleNavigation ( sym , uni ) ;
2017-12-09 03:01:56 +00:00
string & s ( * cfileptr ) ;
2018-06-22 12:47:24 +00:00
int i = isize ( s ) - ( editext ? 0 : 4 ) ;
2018-01-05 13:17:40 +00:00
2017-12-14 11:10:40 +00:00
if ( sym = = SDLK_ESCAPE ) {
2017-12-09 03:01:56 +00:00
popScreen ( ) ;
}
2017-12-14 11:10:40 +00:00
else if ( sym = = SDLK_RETURN | | sym = = SDLK_KP_ENTER ) {
2023-08-09 12:01:24 +00:00
bool ac = file_action ( ) ;
if ( ac ) popScreen ( ) ;
2017-12-14 11:10:40 +00:00
}
2017-12-09 03:01:56 +00:00
else if ( sym = = SDLK_BACKSPACE & & i ) {
2024-06-28 10:20:26 +00:00
int len = utfsize_before ( s , i ) ;
s . erase ( i - len , len ) ;
2022-10-27 10:51:25 +00:00
highlight_text = " //missing " ;
2022-11-03 18:32:12 +00:00
list_skip = 0 ;
2017-12-09 03:01:56 +00:00
}
2024-06-28 10:20:26 +00:00
# if !CAP_SDL2
2017-12-09 03:01:56 +00:00
else if ( uni > = 32 & & uni < 127 ) {
s . insert ( i , s0 + char ( uni ) ) ;
2022-10-27 10:51:25 +00:00
highlight_text = " //missing " ;
2022-11-03 18:32:12 +00:00
list_skip = 0 ;
2017-12-09 03:01:56 +00:00
}
2024-06-28 10:20:26 +00:00
# endif
2018-06-12 20:12:15 +00:00
return ;
2017-12-09 03:01:56 +00:00
}
2019-08-09 19:00:52 +00:00
EX void openFileDialog ( string & filename , string fcap , string ext , bool_reaction_t action ) {
2023-08-09 12:01:24 +00:00
file_dialog fd ;
2017-12-09 03:01:56 +00:00
cfileptr = & filename ;
filecaption = fcap ;
cfileext = ext ;
2017-12-14 11:10:40 +00:00
file_action = action ;
2023-08-09 12:01:24 +00:00
pushScreen ( fd ) ;
2017-12-09 03:01:56 +00:00
}
// infix/v/vpush
2019-08-09 19:00:52 +00:00
EX string infix ;
2017-12-09 03:01:56 +00:00
2021-06-17 07:38:27 +00:00
string foreign_letters = " ÁÄÇÈÉÍÎÖÚÜßàáâãäçèéêìíîïòóôõöøùúüýąćČčĎďĘęĚěğİıŁłńňŘřŚśŞşŠšŤťůŹźŻżŽž " ;
string latin_letters = " AACEEIIOUUsAAAAACEEEIIIIOOOOOOUUUYACCCDDEEEEGIILLNNRRSSSSSSTTUZZZZZZ " ;
2022-11-03 18:33:19 +00:00
EX string human_simplify ( const string & s , bool include_symbols ) {
2017-12-09 03:01:56 +00:00
string t = " " ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( s ) ; i + + ) {
2017-12-09 03:01:56 +00:00
char c = s [ i ] ;
char tt = 0 ;
if ( c > = ' a ' & & c < = ' z ' ) tt + = c - 32 ;
else if ( c > = ' A ' & & c < = ' Z ' ) tt + = c ;
else if ( c = = ' @ ' ) tt + = c ;
2022-11-03 18:33:19 +00:00
else if ( include_symbols & & c > 0 ) tt + = c ;
2021-06-17 07:38:27 +00:00
if ( tt = = 0 ) for ( int k = 0 ; k < isize ( latin_letters ) ; k + + ) {
if ( s [ i ] = = foreign_letters [ 2 * k ] & & s [ i + 1 ] = = foreign_letters [ 2 * k + 1 ] ) {
if ( latin_letters [ k ] = = ' s ' ) t + = " SS " ;
else tt + = latin_letters [ k ] ;
}
}
2017-12-09 03:01:56 +00:00
if ( tt ) t + = tt ;
}
2022-11-03 18:33:19 +00:00
return t ;
2017-12-09 03:01:56 +00:00
}
2022-11-03 18:33:19 +00:00
EX bool hasInfix ( const string & s ) {
if ( infix = = " " ) return true ;
return human_simplify ( s , false ) . find ( infix ) ! = string : : npos ;
}
2022-11-03 18:31:28 +00:00
EX bool has_substring ( const string & s , const string & needle ) {
int spos = 0 , npos = 0 ;
while ( true ) {
if ( npos = = isize ( needle ) ) return true ;
if ( spos = = isize ( s ) ) return false ;
if ( s [ spos + + ] = = needle [ npos ] ) npos + + ;
}
}
2019-08-09 19:00:52 +00:00
EX bool editInfix ( int uni ) {
2017-12-09 03:01:56 +00:00
if ( uni > = ' A ' & & uni < = ' Z ' ) infix + = uni ;
else if ( uni > = ' a ' & & uni < = ' z ' ) infix + = uni - 32 ;
2018-06-22 12:47:24 +00:00
else if ( infix ! = " " & & uni = = 8 ) infix = infix . substr ( 0 , isize ( infix ) - 1 ) ;
2017-12-09 03:01:56 +00:00
else if ( infix ! = " " & & uni ! = 0 ) infix = " " ;
else return false ;
return true ;
}
2019-08-09 19:00:52 +00:00
EX vector < pair < string , color_t > > v ;
2017-12-09 03:01:56 +00:00
2019-08-09 19:00:52 +00:00
EX void vpush ( color_t color , const char * name ) {
2017-12-09 03:01:56 +00:00
string s = XLATN ( name ) ;
if ( ! hasInfix ( s ) ) return ;
2018-09-05 13:18:40 +00:00
dialog : : v . push_back ( make_pair ( s , color ) ) ;
2017-12-09 03:01:56 +00:00
}
2024-08-21 17:22:49 +00:00
EX void vpush2 ( color_t color , const string & name , const string & extra ) {
if ( ! hasInfix ( extra ) ) return ;
dialog : : v . push_back ( make_pair ( name , color ) ) ;
}
2017-12-09 03:01:56 +00:00
2023-08-14 02:36:14 +00:00
EX string editchecker ( int sym , int uni ) {
if ( uni > = 32 & & uni < 127 ) return string ( " " ) + char ( uni ) ;
return " " ;
}
2018-11-06 23:50:03 +00:00
2023-08-14 02:36:14 +00:00
# if HDR
struct string_dialog : extdialog {
int editpos = 0 ;
string * edited_string ;
string view_edited_string ( ) ;
2023-08-21 17:23:48 +00:00
void draw ( ) override ;
2023-08-14 02:36:14 +00:00
void start_editing ( string & s ) ;
bool handle_edit_string ( int sym , int uni , function < string ( int , int ) > checker = editchecker ) ;
2024-06-28 10:20:26 +00:00
void handle_textinput ( ) ;
2023-08-14 02:36:14 +00:00
} ;
# endif
string string_dialog : : view_edited_string ( ) {
2018-11-06 23:50:03 +00:00
string cs = * edited_string ;
if ( editpos < 0 ) editpos = 0 ;
if ( editpos > isize ( cs ) ) editpos = isize ( cs ) ;
cs . insert ( editpos , " ° " ) ;
return cs ;
}
2023-08-14 02:36:14 +00:00
void string_dialog : : start_editing ( string & s ) {
2018-11-06 23:50:03 +00:00
edited_string = & s ;
editpos = isize ( s ) ;
}
2018-11-24 21:49:45 +00:00
2023-08-14 02:36:14 +00:00
bool string_dialog : : handle_edit_string ( int sym , int uni , function < string ( int , int ) > checker ) {
2018-11-06 23:50:03 +00:00
auto & es = * edited_string ;
2018-11-24 21:49:45 +00:00
string u2 ;
2024-06-28 10:20:26 +00:00
if ( DKEY = = SDLK_LEFT ) editpos - = utfsize_before ( es , editpos ) ;
else if ( DKEY = = SDLK_RIGHT ) editpos + = utfsize ( es [ editpos ] ) ;
2018-11-06 23:50:03 +00:00
else if ( uni = = 8 ) {
if ( editpos = = 0 ) return true ;
2024-06-28 10:20:26 +00:00
int len = utfsize_before ( es , editpos ) ;
es . replace ( editpos - len , len , " " ) ;
editpos - = len ;
2023-08-14 02:36:14 +00:00
if ( reaction ) reaction ( ) ;
2018-11-06 23:50:03 +00:00
}
2018-11-24 21:49:45 +00:00
else if ( ( u2 = checker ( sym , uni ) ) ! = " " ) {
2024-06-28 10:20:26 +00:00
# if !CAP_SDL2
2018-11-24 21:49:45 +00:00
for ( char c : u2 ) {
es . insert ( editpos , 1 , c ) ;
editpos + + ;
}
2024-06-28 10:20:26 +00:00
# endif
2023-08-14 02:36:14 +00:00
if ( reaction ) reaction ( ) ;
2018-11-06 23:50:03 +00:00
}
else return false ;
return true ;
}
2023-08-09 12:01:24 +00:00
2024-06-28 10:20:26 +00:00
void string_dialog : : handle_textinput ( ) {
# if CAP_SDL2
texthandler = [ this ] ( const SDL_TextInputEvent & ev ) {
auto & es = * edited_string ;
string txt = ev . text ;
es . insert ( editpos , txt ) ;
editpos + = isize ( txt ) ;
if ( reaction ) reaction ( ) ;
} ;
# endif
}
2023-08-09 12:01:24 +00:00
void string_dialog : : draw ( ) {
2018-11-06 23:50:03 +00:00
cmode = sm : : NUMBER | dialogflags ;
2022-07-05 09:51:06 +00:00
gamescreen ( ) ;
2023-08-09 12:01:24 +00:00
init ( title ) ;
2018-11-06 23:50:03 +00:00
addInfo ( view_edited_string ( ) ) ;
addBreak ( 100 ) ;
2019-07-03 05:31:09 +00:00
formula_keyboard ( true ) ;
addBreak ( 100 ) ;
2018-11-06 23:50:03 +00:00
dialog : : addBack ( ) ;
addBreak ( 100 ) ;
2023-08-09 12:01:24 +00:00
if ( help ! = " " ) {
addHelp ( help ) ;
2018-11-06 23:50:03 +00:00
}
if ( extra_options ) extra_options ( ) ;
display ( ) ;
2023-08-09 12:01:24 +00:00
keyhandler = [ this ] ( int sym , int uni ) {
2018-11-06 23:50:03 +00:00
handleNavigation ( sym , uni ) ;
if ( handle_edit_string ( sym , uni ) ) ;
2023-08-09 12:01:24 +00:00
else if ( doexiton ( sym , uni ) ) popfinal ( ) ;
2018-11-06 23:50:03 +00:00
} ;
2024-06-28 10:20:26 +00:00
handle_textinput ( ) ;
2023-08-09 12:01:24 +00:00
}
2018-11-06 23:50:03 +00:00
2019-08-09 19:00:52 +00:00
EX void edit_string ( string & s , string title , string help ) {
2023-08-09 12:01:24 +00:00
string_dialog ne ;
2018-11-06 23:50:03 +00:00
ne . title = title ;
ne . help = help ;
2023-08-14 02:36:14 +00:00
ne . start_editing ( s ) ;
2023-08-09 12:01:24 +00:00
pushScreen ( ne ) ;
2018-11-06 23:50:03 +00:00
}
2019-08-09 19:00:52 +00:00
EX void confirm_dialog ( const string & text , const reaction_t & act ) {
2022-07-05 09:51:06 +00:00
cmode = sm : : DARKEN ;
gamescreen ( ) ;
2018-12-14 17:21:52 +00:00
dialog : : addBreak ( 250 ) ;
dialog : : init ( XLAT ( " WARNING " ) , 0xFF0000 , 150 , 100 ) ;
2018-12-14 17:22:12 +00:00
dialog : : addHelp ( text ) ;
2018-12-14 17:21:52 +00:00
dialog : : addItem ( XLAT ( " YES " ) , ' y ' ) ;
auto yes = [ act ] ( ) { popScreen ( ) ; act ( ) ; } ;
dialog : : add_action ( yes ) ;
dialog : : add_key_action ( SDLK_RETURN , yes ) ;
dialog : : addItem ( XLAT ( " NO " ) , ' n ' ) ;
dialog : : add_action ( [ ] ( ) { popScreen ( ) ; } ) ;
dialog : : display ( ) ;
}
2022-10-21 08:59:57 +00:00
EX void addBoolItem_action ( const string & s , bool & b , int c ) {
2019-05-03 09:44:15 +00:00
dialog : : addBoolItem ( s , b , c ) ;
dialog : : add_action ( [ & b ] { b = ! b ; } ) ;
}
2019-05-03 10:11:40 +00:00
2022-10-21 08:59:57 +00:00
EX void addBoolItem_action_neg ( const string & s , bool & b , int c ) {
2019-05-03 10:11:40 +00:00
dialog : : addBoolItem ( s , ! b , c ) ;
dialog : : add_action ( [ & b ] { b = ! b ; } ) ;
}
2019-08-09 19:00:52 +00:00
2024-06-29 08:02:50 +00:00
EX void addItem_mouse ( const string & s , key_type c ) {
dialog : : addBoolItem ( s , mousekey = = c , c ) ;
}
2020-05-31 14:43:36 +00:00
EX bool cheat_forbidden ( ) {
if ( tactic : : on & & ! cheater ) {
addMessage ( XLAT ( " Not available in the pure tactics mode! " ) ) ;
return true ;
}
if ( daily : : on ) {
addMessage ( XLAT ( " Not available in the daily challenge! " ) ) ;
return true ;
}
return false ;
}
2020-07-12 18:49:06 +00:00
EX void add_action_confirmed ( const reaction_t & act ) {
dialog : : add_action ( dialog : : add_confirmation ( act ) ) ;
}
2020-05-31 14:43:36 +00:00
2019-08-09 19:00:52 +00:00
# if HDR
template < class T > void addBoolItem_choice ( const string & s , T & b , T val , char c ) {
addBoolItem ( s , b = = val , c ) ;
add_action ( [ & b , val ] { b = val ; } ) ;
}
inline void cheat_if_confirmed ( const reaction_t & act ) {
2020-05-31 14:43:36 +00:00
if ( cheat_forbidden ( ) )
return ;
2019-08-09 19:00:52 +00:00
if ( needConfirmationEvenIfSaved ( ) ) pushScreen ( [ act ] ( ) { confirm_dialog ( XLAT ( " This will enable the cheat mode, making this game ineligible for scoring. Are you sure? " ) , act ) ; } ) ;
else act ( ) ;
}
inline void do_if_confirmed ( const reaction_t & act ) {
if ( needConfirmationEvenIfSaved ( ) ) pushScreen ( [ act ] ( ) { confirm_dialog ( XLAT ( " This will end your current game and start a new one. Are you sure? " ) , act ) ; } ) ;
else act ( ) ;
}
2020-04-17 18:34:49 +00:00
inline void push_confirm_dialog ( const reaction_t & act , const string & s ) {
pushScreen ( [ act , s ] ( ) { confirm_dialog ( s , act ) ; } ) ;
}
2019-08-09 19:00:52 +00:00
inline reaction_t add_confirmation ( const reaction_t & act ) {
return [ act ] { do_if_confirmed ( act ) ; } ;
}
# endif
2020-02-23 01:51:27 +00:00
}
2018-06-10 23:58:31 +00:00
}