Loading...
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright 2022 Google LLC
 * Written by Simon Glass <sjg@chromium.org>
 */

#ifndef __EXPO_H
#define __EXPO_H

#include <abuf.h>
#include <alist.h>
#include <video_defs.h>
#include <dm/ofnode_decl.h>
#include <linux/bitops.h>
#include <linux/list.h>

struct membuf;
struct udevice;

#include <cli.h>

/**
 * enum expo_id_t - standard expo IDs
 *
 * These are assumed to be in use at all times. Expos should use IDs starting
 * from EXPOID_BASE_ID,
 *
 * @EXPOID_NONE: Not used, invalid ID 0
 * @EXPOID_SAVE: User has requested that the expo data be saved
 * @EXPOID_DISCARD: User has requested that the expo data be discarded
 * @EXPOID_BASE_ID: First ID which can be used for expo objects
 */
enum expo_id_t {
	EXPOID_NONE,

	EXPOID_SAVE,
	EXPOID_DISCARD,

	EXPOID_BASE_ID = 5,
};

/**
 * enum expoact_type - types of actions reported by the expo
 *
 * @EXPOACT_NONE: no action
 * @EXPOACT_POINT_OBJ: object was highlighted (@id indicates which object)
 * @EXPOACT_POINT_ITEM: menu item was highlighted (@id indicates which item)
 * @EXPOACT_SELECT: menu item was selected (@id indicates which)
 * @EXPOACT_OPEN: menu was opened, so an item can be selected (@id indicates
 * which menu object)
 * @EXPOACT_CLOSE: menu was closed (@id indicates which menu object)
 * @EXPOACT_POINT_OPEN: menu item was pointed to and menu opened (@id indicates
 * which menu object)
 * @EXPOACT_POINT_CLOSE: menu item was pointed to and menu closed @id indicates
 * which menu item)
 * @EXPOACT_REPOINT_OPEN: menu closed, another menu opened (@prev_id indicates
 * the menu closed, @id indicates menu opened)
 * @EXPOACT_QUIT: request to exit the menu
 * @EXPOACT_CLICK: click on an object
 * @EXPOACT_SETTINGS: select menu settings
 */
enum expoact_type {
	EXPOACT_NONE,
	EXPOACT_POINT_OBJ,
	EXPOACT_POINT_ITEM,
	EXPOACT_SELECT,
	EXPOACT_OPEN,
	EXPOACT_CLOSE,
	EXPOACT_POINT_OPEN,
	EXPOACT_POINT_CLOSE,
	EXPOACT_REPOINT_OPEN,
	EXPOACT_QUIT,
	EXPOACT_CLICK,
	EXPOACT_SETTINGS,
};

/**
 * struct expo_action - an action report by the expo
 *
 * @type: Action type (EXPOACT_NONE if there is no action)
 * @select: Used for all actions except EXPOACT_NONE and EXPOACT_QUIT
 * @select.id: ID number of the object affected
 * @select.prev_id: ID number of the old object that was highlighted
 * @select.changed: true if the selection has changed since last time (only
 * valid for EXPOACT_POINT_ITEM)
 */
struct expo_action {
	enum expoact_type type;
	union {
		struct {
			int id;
			int prev_id;
			bool changed;
		} select;
	};
};

struct expo_test_mode;

/**
 * struct expo_theme - theme for the expo
 *
 * @font_size: Default font size for all text
 * @menu_inset: Inset width (on each side and top/bottom) for menu items
 * @menuitem_gap_y: Gap between menu items in pixels
 * @menu_title_margin_x: Gap between right side of menu title and left size of
 *	menu label
 * @textline_label_margin_x: Gap between right side of textline prompt and left
 *	side of editable text
 * @white_on_black: True to use white-on-black for the expo, false for
 *	black-on-white
 */
struct expo_theme {
	u32 font_size;
	u32 menu_inset;
	u32 menuitem_gap_y;
	u32 menu_title_margin_x;
	u32 textline_label_margin_x;
	bool white_on_black;
};

/**
 * struct expo - information about an expo
 *
 * A group of scenes which can be presented to the user, typically to obtain
 * input or to make a selection.
 *
 * @name: Name of the expo (allocated)
 * @display: Display to use (`UCLASS_VIDEO`), or NULL to use text mode
 * @cons: Console to use (`UCLASS_VIDEO_CONSOLE`), or NULL to use text mode
 * @mouse: Mouse to use (`UCLASS_MOUSE`), or NULL if no mouse
 * @scene_id: Current scene ID (0 if none)
 * @next_id: Next ID number to use, for automatic allocation
 * @action: Action selected by user. At present only one is supported, with the
 * @req_width: Requested width of the display
 * @req_height: Requested height of the display
 * type set to EXPOACT_NONE if there is no action
 * @text_mode: true to use text mode for the menu (no vidconsole)
 * @popup: true to use popup menus, instead of showing all items
 * @show_highlight: show a highlight bar on the selected menu item
 * @mouse_enabled: true if the mouse is enabled
 * @mouse_ptr: Pointer to mouse pointer image data (BMP format)
 * @mouse_size: Size of mouse pointer (width and height in pixels)
 * @mouse_pos: Current mouse position
 * @damage: Bounding box of the area that needs to be redrawn
 * @priv: Private data for the controller
 * @done: Indicates that a cedit session is complete and the user has quit
 * @save: Indicates that cedit data should be saved, rather than discarded
 * @test: Pointer to test mode information, NULL if not allocated
 * @theme: Information about fonts styles, etc.
 * @scene_head: List of scenes
 * @str_head: list of strings
 * @cch: Keyboard context for input
 * @last_key_ms: timestamp of the last key received
 */
struct expo {
	char *name;
	struct udevice *display;
	struct udevice *cons;
	struct udevice *mouse;
	uint scene_id;
	uint next_id;
	struct expo_action action;
	int req_width;
	int req_height;
	bool text_mode;
	bool popup;
	bool show_highlight;
	bool mouse_enabled;
	const void *mouse_ptr;
	struct vid_size mouse_size;
	struct vid_pos mouse_pos;
	struct vid_bbox damage;
	void *priv;
	bool done;
	bool save;
	struct expo_test_mode *test;
	struct expo_theme theme;
	struct list_head scene_head;
	struct list_head str_head;
	struct cli_ch_state cch;
	ulong last_key_ms;
};

/**
 * struct expo_string - a string that can be used in an expo
 *
 * @id: ID number of the string
 * @buf: String (contains nul terminator)
 * @sibling: Node to link this object to its siblings
 */
struct expo_string {
	uint id;
	struct abuf buf;
	struct list_head sibling;
};

/**
 * struct scene - information about a scene in an expo
 *
 * A collection of text/image/menu items in an expo
 *
 * @expo: Expo this scene is part of
 * @name: Name of the scene (allocated)
 * @id: ID number of the scene
 * @title_id: String ID of title of the scene (allocated)
 * @highlight_id: ID of highlighted object, if any
 * @cls: cread state to use for input
 * @buf: Buffer for input
 * @entry_save: Buffer to hold vidconsole text-entry information
 * @sibling: Node to link this scene to its siblings
 * @obj_head: List of objects in the scene
 */
struct scene {
	struct expo *expo;
	char *name;
	uint id;
	uint title_id;
	uint highlight_id;
	struct cli_line_state cls;
	struct abuf buf;
	struct abuf entry_save;
	struct list_head sibling;
	struct list_head obj_head;
};

/**
 * enum scene_obj_t - type of a scene object
 *
 * @SCENEOBJT_NONE: Used to indicate that the type does not matter
 * @SCENEOBJT_IMAGE: Image data to render
 * @SCENEOBJT_BOX: Rectangular box
 * @SCENEOBJT_TEXT: Text line to render
 * @SCENEOBJT_MENU: Menu containing items the user can select
 * @SCENEOBJT_TEXTLINE: Line of text the user can edit
 * @SCENEOBJT_TEXTEDIT: Simple text editor
 */
enum scene_obj_t {
	SCENEOBJT_NONE		= 0,
	SCENEOBJT_IMAGE,
	SCENEOBJT_TEXT,
	SCENEOBJT_BOX,
	SCENEOBJT_TEXTEDIT,

	/* types from here on can be highlighted */
	SCENEOBJT_MENU,
	SCENEOBJT_TEXTLINE,
};

/**
 * struct scene_obj_offset - Offsets for drawing the object
 *
 * Stores the offset from x0, x1 at which objects are drawn
 *
 * @xofs: x offset
 * @yofs: y offset
 */
struct scene_obj_offset {
	int xofs;
	int yofs;
};

/**
 * struct scene_obj_dims - Dimensions of the object being drawn
 *
 * Image and text objects have a dimension which can change depending on what
 * they contain. For images this stores the size. For text it stores the size as
 * rendered on the display
 *
 * @x: x dimension
 * @y: y dimension
 */
struct scene_obj_dims {
	int x;
	int y;
};

/* special values for dimensions */
enum {
	/* width/height of the display */
	SCENEOB_DISPLAY_MAX	= 0x7f000000,
};

/**
 * enum scene_obj_halign - Horizontal alignment of objects
 *
 * Objects are normally drawn on the left size of their bounding box. This
 * properly allows aligning on the right or having the object centred.
 *
 * @SCENEOA_LEFT: Left of object is aligned with its x coordinate
 * @SCENEOA_RIGHT: Right of object is aligned with x + w
 * @SCENEOA_CENTRE: Centre of object is aligned with centre of bounding box
 * @SCENEOA_TOP: Left of object is aligned with its x coordinate
 * @SCENEOA_BOTTOM: Right of object is aligned with x + w
 *
 * Note: It would be nice to make this a char type but Sphinx riddles:
 * ./include/expo.h:258: error: Cannot parse enum!
 * enum scene_obj_align : char {
 */
enum scene_obj_align {
	SCENEOA_LEFT,
	SCENEOA_RIGHT,
	SCENEOA_CENTRE,
	SCENEOA_TOP = SCENEOA_LEFT,
	SCENEOA_BOTTOM = SCENEOA_RIGHT,
};

/**
 * enum scene_obj_flags_t - flags for objects
 *
 * @SCENEOF_HIDE: object should be hidden
 * @SCENEOF_POINT: object should be highlighted
 * @SCENEOF_OPEN: object should be opened (e.g. menu is opened so that an option
 * can be selected)
 * @SCENEOF_SIZE_VALID: object's size (width/height) is valid, so any adjustment
 * to x0/y0 should maintain the width/height of the object
 * @SCENEOF_SYNC_POS: object's position has changed
 * @SCENEOF_SYNC_SIZE: object's size (width/height) has changed
 * @SCENEOF_SYNC_WIDTH: object's widget has changed
 * @SCENEOF_SYNC_BBOX: object's bounding box has changed
 * @SCENEOF_MANUAL: manually arrange the items associated with this object
 * @SCENEOF_DIRTY: object has been modified and needs to be redrawn
 * @SCENEOF_PASSWORD: textline input should show stars instead of characters
 * @SCENEOF_LAST: used just as a check for the size of the flags mask
 */
enum scene_obj_flags_t {
	SCENEOF_HIDE	= 1 << 0,
	SCENEOF_POINT	= 1 << 1,
	SCENEOF_OPEN	= 1 << 2,
	SCENEOF_SIZE_VALID	= BIT(3),
	SCENEOF_SYNC_POS		= BIT(4),
	SCENEOF_SYNC_SIZE	= BIT(5),
	SCENEOF_SYNC_WIDTH	= BIT(6),
	SCENEOF_SYNC_BBOX	= BIT(7),
	SCENEOF_MANUAL		= BIT(8),
	SCENEOF_DIRTY		= BIT(9),
	SCENEOF_PASSWORD	= BIT(10),

	SCENEOF_LAST,	/* check for size of flags below */
};

enum {
	/* Maximum number of characters allowed in an line editor */
	EXPO_MAX_CHARS		= 250,
};

/**
 * struct scene_obj - information about an object in a scene
 *
 * @scene: Scene that this object relates to
 * @name: Name of the object (allocated)
 * @id: ID number of the object
 * @type: Type of this object
 * @req_bbox: Requested bounding box for this object, synced to @bbox when scene is
 * arranged
 * @bbox: Bounding box for this object (internal use only)
 * @ofs: Offset from x0, y0 where the object is drawn (internal use only)
 * @dims: Dimensions of the text/image; may be smaller than bbox
 * (internal use only)
 * @horiz: Horizonal alignment
 * @vert: Vertical alignment
 * @flags: Flags for this object
 * @bit_length: Number of bits used for this object in CMOS RAM
 * @start_bit: Start bit to use for this object in CMOS RAM
 * @sibling: Node to link this object to its siblings
 */
struct scene_obj {
	struct scene *scene;
	char *name;
	uint id;
	enum scene_obj_t type;
	struct vid_bbox req_bbox;
	struct vid_bbox bbox;
	struct scene_obj_offset ofs;
	struct scene_obj_dims dims;
	enum scene_obj_align horiz;
	enum scene_obj_align vert;
	u16 flags;
	u16 start_bit;
	u8 bit_length;
	struct list_head sibling;
};

/* Ensure the largest flag value fits in the flags field */
_Static_assert(SCENEOF_LAST < BIT(sizeof(((struct scene_obj *)0)->flags) * 8),
	       "scene_obj flags exceed flags field capacity");

/* object can be highlighted when moving around expo */
static inline bool scene_obj_can_highlight(const struct scene_obj *obj)
{
	return obj->type >= SCENEOBJT_MENU;
}

/**
 * struct scene_obj_img - information about an image object in a scene
 *
 * This is a rectangular image which is blitted onto the display
 *
 * @obj: Basic object information
 * @data: Image data in BMP format
 */
struct scene_obj_img {
	struct scene_obj obj;
	const char *data;
};

/**
 * struct scene_txt_generic - Generic information common to text objects
 *
 * @str_id: ID of the text string to display
 * @font_name: Name of font (allocated by caller)
 * @font_size: Nominal size of font in pixels
 * @lines: alist of struct vidconsole_mline with a separate record for each
 *	line of text
 */
struct scene_txt_generic {
	uint str_id;
	const char *font_name;
	uint font_size;
	struct alist lines;
};

/**
 * struct scene_obj_txt - information about a text object in a scene
 *
 * This is a single-line text object
 *
 * @obj: Basic object information
 * @gen: Generic information common to all objects which show text
 */
struct scene_obj_txt {
	struct scene_obj obj;
	struct scene_txt_generic gen;
};

/**
 * struct scene_obj_menu - information about a menu object in a scene
 *
 * A menu has a number of items which can be selected by the user
 *
 * It also has:
 *
 * - a text/image object (@pointer_id) which points to the current item
 *   (@cur_item_id)
 *
 * - a preview object which shows an image related to the current item
 *
 * @obj: Basic object information
 * @title_id: ID of the title text object (not string ID), or 0 if none
 * @cur_item_id: ID of the current menu item, or 0 if none
 * @pointer_id: ID of the object pointing to the current selection
 * @pointer_xofs: x position of pointer relative to the left side of the menu
 * @item_head: List of items in the menu
 */
struct scene_obj_menu {
	struct scene_obj obj;
	uint title_id;
	uint cur_item_id;
	uint pointer_id;
	int pointer_xofs;
	struct list_head item_head;
};

/**
 * enum scene_menuitem_flags_t - flags for menu items
 *
 * @SCENEMIF_GAP_BEFORE: Add a gap before this item
 */
enum scene_menuitem_flags_t {
	SCENEMIF_GAP_BEFORE	= 1 << 0,
};

/**
 * struct scene_menitem - a menu item in a menu
 *
 * A menu item has:
 *
 * - text object holding the name (short) and description (can be longer)
 * - a text object holding the keypress
 *
 * @name: Name of the item (this is allocated by this call)
 * @id: ID number of the object
 * @key_id: ID of text object to use as the keypress to show
 * @label_id: ID of text object to use as the label text
 * @desc_id: ID of text object to use as the description text
 * @preview_id: ID of the preview object, or 0 if none
 * @flags: Flags for this item
 * @value: Value for this item, or INT_MAX to use sequence
 * @sibling: Node to link this item to its siblings
 */
struct scene_menitem {
	char *name;
	uint id;
	uint key_id;
	uint label_id;
	uint desc_id;
	uint preview_id;
	uint flags;
	int value;
	struct list_head sibling;
};

/**
 * struct scene_obj_textline - information about a textline in a scene
 *
 * A textline has a prompt and a line of editable text
 *
 * @obj: Basic object information
 * @label_id: ID of the label text object (not string ID), or 0 if none
 * @edit_id: ID of the editable text object (not string ID)
 * @max_chars: Maximum number of characters allowed
 * @buf: Text buffer containing current text
 * @pos: Cursor position
 */
struct scene_obj_textline {
	struct scene_obj obj;
	uint label_id;
	uint edit_id;
	uint max_chars;
	struct abuf buf;
	uint pos;
};

/**
 * struct scene_obj_box - information about a box in a scene
 *
 * A box surrounds a part of the screen with a border
 *
 * @obj: Basic object information
 * @width: Line-width in pixels
 * @fill: true to fill the box, false to draw outline only
 */
struct scene_obj_box {
	struct scene_obj obj;
	uint width;
	bool fill;
};

/**
 * struct scene_obj_txtedit - information about a box in a scene
 *
 * A text editor which allows users to edit a small text file
 *
 * @obj: Basic object information
 * @gen: Generic information common to all objects which show text
 * @buf: Text buffer containing current text
 */
struct scene_obj_txtedit {
	struct scene_obj obj;
	struct scene_txt_generic gen;
	struct abuf buf;
};

/**
 * struct expo_arrange_info - Information used when arranging a scene
 *
 * @label_width: Maximum width of labels in scene
 */
struct expo_arrange_info {
	int label_width;
};

/**
 * expo_new() - create a new expo
 *
 * Allocates a new expo
 *
 * @name: Name of expo (this is allocated by this call)
 * @priv: Private data for the controller
 * @expp: Returns a pointer to the new expo on success
 * Returns: 0 if OK, -ENOMEM if out of memory
 */
int expo_new(const char *name, void *priv, struct expo **expp);

/**
 * expo_destroy() - Destroy an expo and free all its memory
 *
 * @exp: Expo to destroy
 */
void expo_destroy(struct expo *exp);

/**
 * expo_set_dynamic_start() - Set the start of the 'dynamic' IDs
 *
 * It is common for a set of 'static' IDs to be used to refer to objects in the
 * expo. These typically use an enum so that they are defined in sequential
 * order.
 *
 * Dynamic IDs (for objects not in the enum) are intended to be used for
 * objects to which the code does not need to refer. These are ideally located
 * above the static IDs.
 *
 * Use this function to set the start of the dynamic range, making sure that the
 * value is higher than all the statically allocated IDs.
 *
 * @exp: Expo to update
 * @dyn_start: Start ID that expo should use for dynamic allocation
 */
void expo_set_dynamic_start(struct expo *exp, uint dyn_start);

/**
 * expo_str() - add a new string to an expo
 *
 * @exp: Expo to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @str: Pointer to text to display (allocated by caller)
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int expo_str(struct expo *exp, const char *name, uint id, const char *str);

/**
 * expo_get_str() - Get a string by ID
 *
 * @exp: Expo to use
 * @id: String ID to look up
 * @returns string, or NULL if not found
 */
const char *expo_get_str(struct expo *exp, uint id);

/**
 * expo_edit_str() - Make a string writeable
 *
 * This allows a string to be updated under the control of the caller. The
 * buffer must remain valid while the expo is active.
 *
 * @exp: Expo to use
 * @id: String ID to look up
 * @orig: If non-NULL, returns the original buffer, which can be used by the
 *	caller. It is no-longer used by expo so must be uninited by the caller.
 *	It contains a snapshot of the string contents
 * @copyp: Returns a pointer to the new, writeable buffer
 * Return: 0 if OK, -ENOENT if the id was not found, -ENOMEM if out of memory
 */
int expo_edit_str(struct expo *exp, uint id, struct abuf *orig,
		  struct abuf **copyp);

/**
 * expo_set_display() - set the display to use for a expo
 *
 * @exp: Expo to update
 * @dev: Display to use (`UCLASS_VIDEO`), NULL to use text mode
 * Returns: 0 (always)
 */
int expo_set_display(struct expo *exp, struct udevice *dev);

/**
 * expo_calc_dims() - Calculate the dimensions of the objects
 *
 * Updates the width and height of all objects based on their contents
 *
 * @exp: Expo to update
 * Returns 0 if OK, -ENOTSUPP if there is no graphical console
 */
int expo_calc_dims(struct expo *exp);

/**
 * expo_set_scene_id() - Set the current scene ID
 *
 * @exp: Expo to update
 * @scene_id: New scene ID to use (0 to select no scene)
 * Returns: 0 if OK, -ENOENT if there is no scene with that ID
 */
int expo_set_scene_id(struct expo *exp, uint scene_id);

/**
 * expo_first_scene_id() - Get the ID of the first scene
 *
 * @exp: Expo to check
 * Returns: Scene ID of first scene, or -ENOENT if there are no scenes
 */
int expo_first_scene_id(struct expo *exp);

/**
 * expo_render() - render the expo on the display / console
 *
 * @exp: Expo to render
 *
 * Returns: 0 if OK, -ECHILD if there is no current scene, -ENOENT if the
 * current scene is not found, other error if something else goes wrong
 */
int expo_render(struct expo *exp);

/**
 * expo_render_dirty() - render the dirty portion of expo on the display
 *
 * Only the objects within the damage bbox are rendered. The others are
 * assumed to be up-to-date.
 *
 * @exp: Expo to render
 * Return: 0 if OK, -ECHILD if there is no current scene, -ENOENT if the
 * current scene is not found, other error if something else goes wrong
 */
int expo_render_dirty(struct expo *exp);

/**
 * expo_arrange() - Arrange the current scene to deal with object sizes
 *
 * Updates any menus in the current scene so that their objects are in the right
 * place. Does nothing if there is no scene
 *
 * @exp: Expo to arrange
 * Returns: 0 if OK, -ve on error
 */
int expo_arrange(struct expo *exp);

/**
 * expo_set_text_mode() - Controls whether the expo renders in text mode
 *
 * @exp: Expo to update
 * @text_mode: true to use text mode, false to use the console
 */
void expo_set_text_mode(struct expo *exp, bool text_mode);

/**
 * expo_set_mouse_enable() - Controls whether the expo enables mouse input
 *
 * @exp: Expo to update
 * @enable: true to enable mouse input, false to disable
 * Returns: 0 if OK, or -ve error if no mouse found
 */
int expo_set_mouse_enable(struct expo *exp, bool enable);

/**
 * scene_new() - create a new scene in a expo
 *
 * The scene is given the ID @id which must be unique across all scenes, objects
 * and items. The expo's @next_id is updated to at least @id + 1
 *
 * @exp: Expo to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new scene (0 to allocate one)
 * @scnp: Returns a pointer to the new scene on success
 * Returns: ID number for the scene (typically @id), or -ve on error
 */
int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp);

/**
 * expo_lookup_scene_id() - Look up a scene by ID
 *
 * @exp: Expo to check
 * @scene_id: Scene ID to look up
 * @returns pointer to scene if found, else NULL
 */
struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id);

/**
 * scene_highlight_first() - Highlight the first item in a scene
 *
 * This highlights the first item, so that the user can see that it is pointed
 * to
 *
 * @scn: Scene to update
 */
void scene_highlight_first(struct scene *scn);

/**
 * scene_set_highlight_id() - Set the object which is highlighted
 *
 * Sets a new object to highlight in the scene
 *
 * @scn: Scene to update
 * @id: ID of object to highlight
 */
void scene_set_highlight_id(struct scene *scn, uint id);

/**
 * scene_img_set_data() - Set the image data for an image object
 *
 * @scn: Scene to update
 * @id: ID of existing image obejct
 * @data: Image data to use
 * @size: Size of image data
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_img_set_data(struct scene *scn, uint id, const void *data, int size);

/**
 * scene_set_open() - Set whether an item is open or not
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @open: true to open the object, false to close it
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_set_open(struct scene *scn, uint id, bool open);

/**
 * scene_obj_count() - Count the number of objects in a scene
 *
 * @scn: Scene to check
 * Returns: number of objects in the scene, 0 if none
 */
int scene_obj_count(struct scene *scn);

/**
 * scene_img() - add a new image to a scene
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @data: Pointer to image data
 * @imgp: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_img(struct scene *scn, const char *name, uint id, char *data,
	      struct scene_obj_img **imgp);

/**
 * scene_txt() - add a new text object to a scene
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @str_id: ID of the string to use
 * @txtp: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
	      struct scene_obj_txt **txtp);

/**
 * scene_txt_str() - add a new string to expo and text object to a scene
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @str_id: ID of the string to use
 * @str: Pointer to text to display (allocated by caller)
 * @txtp: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
		  const char *str, struct scene_obj_txt **txtp);

/**
 *  scene_menu() - create a menu
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @menup: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_menu(struct scene *scn, const char *name, uint id,
	       struct scene_obj_menu **menup);

/**
 *  scene_textline() - create a textline
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @max_chars: Maximum length of the textline in characters
 * @tlinep: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars,
		   struct scene_obj_textline **tlinep);

/**
 *  scene_box() - create a box
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @width: Line-width in pixels
 * @fill: true to fill the box, false to draw outline only
 * @boxp: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_box(struct scene *scn, const char *name, uint id, uint width,
	      bool fill, struct scene_obj_box **boxp);

/**
 * scene_box_set_fill() - Set the fill property of a box object
 *
 * @scn: Scene containing the box
 * @id: ID of the box object to update
 * @fill: true to fill the box, false to draw outline only
 * Returns: 0 if OK, -ENOENT if the object is not found or is not a box
 */
int scene_box_set_fill(struct scene *scn, uint id, bool fill);

/**
 *  scene_texted() - create a text editor
 *
 * @scn: Scene to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @strid: ID of the string to edit
 * @teditp: If non-NULL, returns the new object
 * Returns: ID number for the object (typically @id), or -ve on error
 */
int scene_texted(struct scene *scn, const char *name, uint id, uint strid,
		 struct scene_obj_txtedit **teditp);

/**
 * scene_txt_set_font() - Set the font for an object
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @font_name: Font name to use (allocated by caller)
 * @font_size: Font size to use (nominal height in pixels)
 */
int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
		       uint font_size);

/**
 * scene_txted_set_font() - Set the font for an object
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @font_name: Font name to use (allocated by caller)
 * @font_size: Font size to use (nominal height in pixels)
 */
int scene_txted_set_font(struct scene *scn, uint id, const char *font_name,
			 uint font_size);

/**
 * scene_obj_set_pos() - Set the postion of an object
 *
 * The given position is marked as 'requested' and will be applied when the
 * scene is next arranged
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @x: x position, in pixels from left side
 * @y: y position, in pixels from top
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_pos(struct scene *scn, uint id, int x, int y);

/**
 * scene_obj_set_size() - Set the size of an object
 *
 * The given size is marked as 'requested' and will be applied when the scene
 * is next arranged
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @w: width in pixels
 * @h: height in pixels
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_size(struct scene *scn, uint id, int w, int h);

/**
 * scene_obj_set_width_flags() - Set the width of an object, with flags
 *
 * The given width is marked as 'requested' and will be applied when the scene
 * is next arranged. The object flags are ORed with @flags
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @w: width in pixels
 * @flags: Flags to OR with the current flags
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_width_flags(struct scene *scn, uint id, int w, uint flags);

/**
 * scene_obj_set_width() - Set the width of an object
 *
 * The given width is marked as 'requested' and will be applied when the scene
 * is next arranged
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @w: width in pixels
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_width(struct scene *scn, uint id, int w);

/**
 * scene_obj_set_bbox() - Set the bounding box of an object
 *
 * The given bounding box is marked as 'requested' and will be applied when the
 * scene is next arranged
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @x0: x position, in pixels from left side
 * @y0: y position, in pixels from top
 * @x1: ending x position (right side)
 * @y1: ending y position (botton side)
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_bbox(struct scene *scn, uint id, int x0, int y0, int x1,
		       int y1);

/**
 * scene_obj_set_halign() - Set the horizontal alignment of an object
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @aln: Horizontal alignment to use
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_halign(struct scene *scn, uint id, enum scene_obj_align aln);

/**
 * scene_obj_set_valign() - Set the vertical alignment of an object
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @aln: Vertical alignment to use
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_valign(struct scene *scn, uint id, enum scene_obj_align aln);

/**
 * scene_obj_set_hide() - Set whether an object is hidden
 *
 * The update happens when the expo is next rendered.
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @hide: true to hide the object, false to show it
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_hide(struct scene *scn, uint id, bool hide);

/**
 * scene_obj_set_manual() - Set whether an object arranges its dependents
 *
 * When this is enabled, scene_arrange() will refrain from moving objects
 * attached to this one. E.g. for a menu, normally it moves text objects
 * associated with the menu.
 *
 * @scn: Scene to update
 * @id: ID of object to update
 * @manual: true to disable arrange dependents when this object is updated
 * Returns: 0 if OK, -ENOENT if @id is invalid
 */
int scene_obj_set_manual(struct scene *scn, uint id, bool manual);

/**
 * scene_menu_set_title() - Set the title of a menu
 *
 * @scn: Scene to update
 * @id: ID of menu object to update
 * @title_id: ID of text object to use as the title
 * Returns: 0 if OK, -ENOENT if @id is invalid, -EINVAL if @title_id is invalid
 */
int scene_menu_set_title(struct scene *scn, uint id, uint title_id);

/**
 * scene_menu_set_pointer() - Set the item pointer for a menu
 *
 * This is a visual indicator of the current item, typically a ">" character
 * which sits next to the current item and moves when the user presses the
 * up/down arrow keys
 *
 * @scn: Scene to update
 * @id: ID of menu object to update
 * @cur_item_id: ID of text or image object to use as a pointer to the current
 * item
 * Returns: 0 if OK, -ENOENT if @id is invalid, -EINVAL if @cur_item_id is invalid
 */
int scene_menu_set_pointer(struct scene *scn, uint id, uint cur_item_id);

/**
 * scene_menu_select_item() - move the pointer/highlight to an item
 *
 * @scn: Scene to update
 * @id: ID of menu object to update
 * @sel_id: ID of the menuitem to select
 * Return 0 on success, -ENOENT if there was no such item
 */
int scene_menu_select_item(struct scene *scn, uint id, uint sel_id);

/**
 * scene_menu_get_cur_item() - get the currently pointed-to item
 *
 * @scn: Scene to update
 * @id: ID of menu object to update
 * Return ID of the current item the menu is pointing to, -ENOENT if @id is not
 * valid, 0 if no item is pointed to
 */
int scene_menu_get_cur_item(struct scene *scn, uint id);

/**
 * scene_obj_get_hw() - Get width and height of an object in a scene
 *
 * @scn: Scene to check
 * @id: ID of menu object to check
 * @widthp: If non-NULL, returns width of object in pixels
 * Returns: Height of object in pixels
 */
int scene_obj_get_hw(struct scene *scn, uint id, int *widthp);

/**
 * scene_menuitem() - Add an item to a menu
 *
 * @scn: Scene to update
 * @menu_id: ID of menu object to update
 * @name: Name to use (this is allocated by this call)
 * @id: ID to use for the new object (0 to allocate one)
 * @key_id: ID of text object to use as the keypress to show
 * @label_id: ID of text object to use as the label text
 * @desc_id: ID of text object to use as the description text
 * @preview_id: ID of object to use as the preview (text or image)
 * @flags: Flags for this item (enum scene_menuitem_flags_t)
 * @itemp: If non-NULL, returns the new object
 * Returns: ID number for the item (typically @id), or -ve on error
 */
int scene_menuitem(struct scene *scn, uint menu_id, const char *name, uint id,
		   uint key_id, uint label_id, uint desc_id, uint preview_id,
		   uint flags, struct scene_menitem **itemp);

/**
 * scene_arrange() - Arrange the scene to deal with object sizes
 *
 * Updates any menus in the scene so that their objects are in the right place.
 *
 * @scn: Scene to arrange
 * Returns: 0 if OK, -ve on error
 */
int scene_arrange(struct scene *scn);

/**
 * expo_send_key() - set a keypress to the expo
 *
 * This processes the key, taking any action that is needed, such as moving
 * between menu items or editing the text in a textline
 *
 * @exp: Expo to receive the key
 * @key: Key to send (ASCII or enum bootmenu_key)
 * Returns: 0 if OK, -ECHILD if there is no current scene
 */
int expo_send_key(struct expo *exp, int key);

/**
 * expo_send_click() - send a mouse click to the expo
 *
 * @exp: Expo to receive the click
 * @x: X coordinate of click
 * @y: Y coordinate of click
 * Returns: 0 if OK, -ECHILD if there is no current scene
 */
int expo_send_click(struct expo *exp, int x, int y);

/**
 * expo_action_get() - read user input from the expo
 *
 * @exp: Expo to check
 * @act: Returns action
 * Returns: 0 if OK, -EAGAIN if there was no action to return
 */
int expo_action_get(struct expo *exp, struct expo_action *act);

/**
 * expo_setup_theme() - Read a theme from a node and apply it to an expo
 *
 * @exp: Expo to update
 * @node: Node containing the theme
 * Returns: 0 if OK, -ve on error
 */
int expo_setup_theme(struct expo *exp, ofnode node);

/**
 * expo_apply_theme() - Apply an expo's theme
 *
 * The theme to be applied must be set up exp->theme
 *
 * @exp: Expo to update
 * @do_objs: Apply theme to objects as well (normally this should be true)
 * Returns: 0 if OK, -ve on error
 */
int expo_apply_theme(struct expo *exp, bool do_objs);

/**
 * expo_build() - Build an expo from an FDT description
 *
 * Build a complete expo from a description in the provided devicetree.
 *
 * See doc/develop/expo.rst for a description of the format
 *
 * @root: Root node for expo description
 * @expp: Returns the new expo
 * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
 * error, -ENOENT if there is a references to a non-existent string
 */
int expo_build(ofnode root, struct expo **expp);

/**
 * cb_expo_build() - Build an expo for coreboot CMOS RAM
 *
 * @expp: Returns the expo created
 * Return: 0 if OK, -ve on error
 */
int cb_expo_build(struct expo **expp);

/**
 * expo_poll() - see if the user takes an action
 *
 * This checks for a keypress. If there is one, it is processed and the
 * resulting action returned, if any.
 *
 * Note that expo_render() should normally be called immediately before this
 * function so that the user can see the latest state.
 *
 * @exp: Expo to poll
 * @act: Returns action on success
 * Return: 0 if an action was obtained, -EAGAIN if not, other error if something
 *	went wrong
 */
int expo_poll(struct expo *exp, struct expo_action *act);

/**
 * expo_req_size() - Request a size for the expo display
 *
 * Set the width and height of the display, so far as requested positions and
 * size are concerned. The actual display may be larger or smaller, in which
 * case expo scales the objects to fit
 *
 * @exp: Expo to update
 * @width: Requested display width
 * @height: Requested display height
 */
void expo_req_size(struct expo *exp, int width, int height);

/**
 * expo_enter_mode() - Enter expo mode for the video subsystem
 *
 * @exp: Expo to update
 *
 * This suppresses automatic video sync operations to allow expo to control
 * rendering timing. Should be called before starting the expo loop.
 */
void expo_enter_mode(struct expo *exp);

/**
 * expo_exit_mode() - Exit expo mode for the video subsystem
 *
 * @exp: Expo to update
 *
 * This restores normal video sync operations. Should be called after
 * finishing the expo loop.
 */
void expo_exit_mode(struct expo *exp);

/**
 * expo_damage_reset() - Reset the damage tracking area
 *
 * @exp: Expo to reset damage tracking for
 *
 * Clears the damage area, indicating that no part of the display needs
 * to be redrawn.
 */
void expo_damage_reset(struct expo *exp);

/**
 * expo_damage_add() - Add a damaged area to the expo damage tracking
 *
 * @exp: Expo to add damage to
 * @bbox: Bounding box of the damaged area to add
 *
 * Expands the current damage area to include the new damaged region.
 * If there is no existing damage, the damage area is set to the new region.
 */
void expo_damage_add(struct expo *exp, const struct vid_bbox *bbox);

/**
 * expo_dump() - Dump expo structure to a membuf
 *
 * @mb: membuf to write to
 * @exp: Expo to dump
 */
void expo_dump(struct expo *exp, struct membuf *mb);

/**
 * scene_dump() - Dump scene structure to a membuf
 *
 * @mb: membuf to write to
 * @scn: Scene to dump
 * @indent: Indentation level
 */
void scene_dump(struct membuf *mb, struct scene *scn, int indent);

#endif /*__EXPO_H */