88hidden global objects within libtcod. If you begin using contexts then
99most of these functions will no longer work properly.
1010
11- Instead of calling :any:`tcod.console_init_root` you can call either
12- :any:`tcod.context.new_window` or :any:`tcod.context.new_terminal` depending
13- on how you plan to setup the size of the console. You should use
11+ Instead of calling :any:`tcod.console_init_root` you can call
12+ :any:`tcod.context.new` with different keywords depending on how you plan
13+ to setup the size of the console. You should use
1414:any:`tcod.tileset` to load the font for a context.
1515
1616.. note::
5050import sys
5151import os
5252
53- from typing import Any , Optional , Tuple
53+ from typing import Any , Iterable , List , Optional , Tuple
5454
5555import tcod
56- from tcod ._internal import _check , _check_warn
56+ from tcod ._internal import _check , _check_warn , deprecate
5757from tcod .loader import ffi , lib
5858import tcod .event
5959import tcod .tileset
@@ -129,11 +129,14 @@ def _handle_tileset(tileset: Optional[tcod.tileset.Tileset]) -> Any:
129129 return tileset ._tileset_p if tileset else ffi .NULL
130130
131131
132- def _handle_title (title : Optional [str ]) -> str :
133- """Return title, or if title is None then return a decent default title."""
132+ def _handle_title (title : Optional [str ]) -> Any :
133+ """Return title as a CFFI string.
134+
135+ If title is None then return a decent default title is returned.
136+ """
134137 if title is None :
135138 title = os .path .basename (sys .argv [0 ])
136- return title
139+ return ffi . new ( "char[]" , title . encode ( "utf-8" ))
137140
138141
139142class Context :
@@ -197,20 +200,22 @@ def present(
197200 upper-left corner. Values of 0.5 will center the console.
198201 """
199202 clear_rgba = (clear_color [0 ], clear_color [1 ], clear_color [2 ], 255 )
200- options = {
201- "keep_aspect" : keep_aspect ,
202- "integer_scaling" : integer_scaling ,
203- "clear_color" : clear_rgba ,
204- "align_x" : align [0 ],
205- "align_y" : align [1 ],
206- }
207- console_p = console .console_c
208- with ffi .new ("struct TCOD_ViewportOptions*" , options ) as viewport_opts :
209- _check (
210- lib .TCOD_context_present (
211- self ._context_p , console_p , viewport_opts
212- )
203+ viewport_args = ffi .new (
204+ "TCOD_ViewportOptions*" ,
205+ {
206+ "tcod_version" : lib .TCOD_COMPILEDVERSION ,
207+ "keep_aspect" : keep_aspect ,
208+ "integer_scaling" : integer_scaling ,
209+ "clear_color" : clear_rgba ,
210+ "align_x" : align [0 ],
211+ "align_y" : align [1 ],
212+ },
213+ )
214+ _check (
215+ lib .TCOD_context_present (
216+ self ._context_p , console .console_c , viewport_args
213217 )
218+ )
214219
215220 def pixel_to_tile (self , x : int , y : int ) -> Tuple [int , int ]:
216221 """Convert window pixel coordinates to tile coordinates."""
@@ -316,19 +321,39 @@ def toggle_fullscreen(context: tcod.context.Context) -> None:
316321 return lib .TCOD_context_get_sdl_window (self ._context_p )
317322
318323
319- def new_window (
320- width : int ,
321- height : int ,
324+ @ffi .def_extern () # type: ignore
325+ def _pycall_cli_output (catch_reference : Any , output : Any ) -> None :
326+ """Callback for the libtcod context CLI. Catches the CLI output."""
327+ catch = ffi .from_handle (catch_reference ) # type: List[str]
328+ catch .append (ffi .string (output ).decode ("utf-8" ))
329+
330+
331+ def new (
322332 * ,
333+ x : Optional [int ] = None ,
334+ y : Optional [int ] = None ,
335+ width : Optional [int ] = None ,
336+ height : Optional [int ] = None ,
337+ columns : Optional [int ] = None ,
338+ rows : Optional [int ] = None ,
323339 renderer : Optional [int ] = None ,
324340 tileset : Optional [tcod .tileset .Tileset ] = None ,
325341 vsync : bool = True ,
326342 sdl_window_flags : Optional [int ] = None ,
327- title : Optional [str ] = None
343+ title : Optional [str ] = None ,
344+ argv : Optional [Iterable [str ]] = None
328345) -> Context :
329346 """Create a new context with the desired pixel size.
330347
331- `width` and `height` is the desired pixel resolution of the window.
348+ `x`, `y`, `width`, and `height` are the desired position and size of the
349+ window. If these are None then they will be derived from `columns` and
350+ `rows`. So if you plan on having a console of a fixed size then you should
351+ set `columns` and `rows` instead of the window keywords.
352+
353+ `columns` and `rows` is the desired size of the console. Can be left as
354+ `None` when you're setting a context by a window size instead of a console.
355+
356+ Providing no size information at all is also acceptable.
332357
333358 `renderer` is the desired libtcod renderer to use.
334359 Typical options are :any:`tcod.context.RENDERER_OPENGL2` for a faster
@@ -348,32 +373,95 @@ def new_window(
348373
349374 `title` is the desired title of the window.
350375
351- After the context is created you can use
352- :any:`Context.recommended_console_size` to figure out the size of the
353- console for the context.
376+ `argv` these arguments are passed to libtcod and allow an end-user to make
377+ last second changes such as forcing fullscreen or windowed mode, or
378+ changing the libtcod renderer.
379+ By default this will pass in `sys.argv` but you can disable this feature
380+ by providing an empty list instead.
381+ Certain commands such as ``-help`` will raise a SystemExit exception from
382+ this function with the output message.
383+
384+ When a window size is given instead of a console size then you can use
385+ :any:`Context.recommended_console_size` to automatically find the size of
386+ the console which should be used.
387+
388+ .. versionadded:: 11.16
354389 """
355- context_pp = ffi .new ("TCOD_Context**" )
356390 if renderer is None :
357- renderer = RENDERER_SDL2
391+ renderer = RENDERER_OPENGL2
358392 if sdl_window_flags is None :
359393 sdl_window_flags = SDL_WINDOW_RESIZABLE
360- tileset_p = _handle_tileset (tileset )
361- title = _handle_title (title )
362- _check_warn (
363- lib .TCOD_context_new_window (
364- width ,
365- height ,
366- renderer ,
367- tileset_p ,
368- vsync ,
369- sdl_window_flags ,
370- title .encode ("utf-8" ),
371- context_pp ,
372- )
394+ if argv is None :
395+ argv = sys .argv
396+ argv_encoded = [ # Needs to be kept alive for argv_c.
397+ ffi .new ("char[]" , arg .encode ("utf-8" )) for arg in argv
398+ ]
399+ argv_c = ffi .new ("char*[]" , argv_encoded )
400+
401+ catch_msg = [] # type: List[str]
402+ catch_handle = ffi .new_handle (catch_msg ) # Keep alive.
403+
404+ params = ffi .new (
405+ "struct TCOD_ContextParams*" ,
406+ {
407+ "tcod_version" : lib .TCOD_COMPILEDVERSION ,
408+ "x" : x if x is not None else lib .SDL_WINDOWPOS_UNDEFINED ,
409+ "y" : y if y is not None else lib .SDL_WINDOWPOS_UNDEFINED ,
410+ "pixel_width" : width or 0 ,
411+ "pixel_height" : height or 0 ,
412+ "columns" : columns or 0 ,
413+ "rows" : rows or 0 ,
414+ "renderer_type" : renderer ,
415+ "tileset" : _handle_tileset (tileset ),
416+ "vsync" : vsync ,
417+ "sdl_window_flags" : sdl_window_flags ,
418+ "window_title" : _handle_title (title ),
419+ "argc" : len (argv_c ),
420+ "argv" : argv_c ,
421+ "cli_output" : ffi .addressof (lib , "_pycall_cli_output" ),
422+ "cli_userdata" : catch_handle ,
423+ },
373424 )
425+ context_pp = ffi .new ("TCOD_Context**" )
426+ error = lib .TCOD_context_new (params , context_pp )
427+ if error == lib .TCOD_E_REQUIRES_ATTENTION :
428+ raise SystemExit (catch_msg [0 ])
429+ _check_warn (error )
374430 return Context ._claim (context_pp [0 ])
375431
376432
433+ @deprecate (
434+ "Call tcod.context.new with width and height as keyword parameters."
435+ )
436+ def new_window (
437+ width : int ,
438+ height : int ,
439+ * ,
440+ renderer : Optional [int ] = None ,
441+ tileset : Optional [tcod .tileset .Tileset ] = None ,
442+ vsync : bool = True ,
443+ sdl_window_flags : Optional [int ] = None ,
444+ title : Optional [str ] = None
445+ ) -> Context :
446+ """Create a new context with the desired pixel size.
447+
448+ .. deprecated:: 11.16
449+ :any:`tcod.context.new` provides more options, such as window position.
450+ """
451+ return new (
452+ width = width ,
453+ height = height ,
454+ renderer = renderer ,
455+ tileset = tileset ,
456+ vsync = vsync ,
457+ sdl_window_flags = sdl_window_flags ,
458+ title = title ,
459+ )
460+
461+
462+ @deprecate (
463+ "Call tcod.context.new with columns and rows as keyword parameters."
464+ )
377465def new_terminal (
378466 columns : int ,
379467 rows : int ,
@@ -386,31 +474,15 @@ def new_terminal(
386474) -> Context :
387475 """Create a new context with the desired console size.
388476
389- `columns` and `rows` are the desired size of the console.
390-
391- The remaining parameters are the same as :any:`new_window`.
392-
393- You can use this instead of :any:`new_window` if you plan on using a
394- :any:`tcod.Console` of a fixed size. This function is the most similar to
395- :any:`tcod.console_init_root`.
477+ .. deprecated:: 11.16
478+ :any:`tcod.context.new` provides more options.
396479 """
397- context_pp = ffi .new ("TCOD_Context**" )
398- if renderer is None :
399- renderer = RENDERER_SDL2
400- if sdl_window_flags is None :
401- sdl_window_flags = SDL_WINDOW_RESIZABLE
402- tileset_p = _handle_tileset (tileset )
403- title = _handle_title (title )
404- _check_warn (
405- lib .TCOD_context_new_terminal (
406- columns ,
407- rows ,
408- renderer ,
409- tileset_p ,
410- vsync ,
411- sdl_window_flags ,
412- title .encode ("utf-8" ),
413- context_pp ,
414- )
480+ return new (
481+ columns = columns ,
482+ rows = rows ,
483+ renderer = renderer ,
484+ tileset = tileset ,
485+ vsync = vsync ,
486+ sdl_window_flags = sdl_window_flags ,
487+ title = title ,
415488 )
416- return Context ._claim (context_pp [0 ])
0 commit comments