@@ -1026,6 +1026,271 @@ impl HwpWriter {
10261026 pub fn document ( & self ) -> & HwpDocument {
10271027 & self . document
10281028 }
1029+
1030+ /// Get current page layout
1031+ pub fn get_page_layout ( & self ) -> Option < crate :: model:: page_layout:: PageLayout > {
1032+ self . document
1033+ . body_texts
1034+ . get ( self . current_section_idx ) ?
1035+ . sections
1036+ . get ( 0 ) ?
1037+ . page_def
1038+ . as_ref ( )
1039+ . map ( |pd| pd. get_layout ( ) )
1040+ }
1041+
1042+ /// Set paper size (alias for set_page_layout with standard sizes)
1043+ pub fn set_paper_size ( & mut self , size : & str ) -> Result < ( ) > {
1044+ match size. to_lowercase ( ) . as_str ( ) {
1045+ "a4" => self . set_a4_portrait ( ) ,
1046+ "a4-landscape" => self . set_a4_landscape ( ) ,
1047+ "letter" => self . set_letter_portrait ( ) ,
1048+ "letter-landscape" => self . set_letter_landscape ( ) ,
1049+ _ => Err ( crate :: error:: HwpError :: InvalidInput ( format ! (
1050+ "Unknown paper size: {}" ,
1051+ size
1052+ ) ) ) ,
1053+ }
1054+ }
1055+
1056+ /// Set page orientation
1057+ pub fn set_page_orientation ( & mut self , landscape : bool ) -> Result < ( ) > {
1058+ let current_layout = self . get_page_layout ( ) . unwrap_or_default ( ) ;
1059+ let new_layout = if landscape {
1060+ crate :: model:: page_layout:: PageLayout {
1061+ width : current_layout. height ,
1062+ height : current_layout. width ,
1063+ ..current_layout
1064+ }
1065+ } else {
1066+ crate :: model:: page_layout:: PageLayout {
1067+ width : current_layout. width . min ( current_layout. height ) ,
1068+ height : current_layout. width . max ( current_layout. height ) ,
1069+ ..current_layout
1070+ }
1071+ } ;
1072+ self . set_page_layout ( new_layout)
1073+ }
1074+
1075+ /// Add a simple footer (without page number)
1076+ pub fn add_footer ( & mut self , text : & str ) {
1077+ self . add_footer_with_page_number ( text, crate :: model:: PageNumberFormat :: Numeric ) ;
1078+ }
1079+
1080+ /// Add header with page number
1081+ pub fn add_header_with_page_number (
1082+ & mut self ,
1083+ text : & str ,
1084+ format : crate :: model:: PageNumberFormat ,
1085+ ) {
1086+ if let Some ( body_text) = self . document . body_texts . get_mut ( self . current_section_idx ) {
1087+ if let Some ( section) = body_text. sections . get_mut ( 0 ) {
1088+ if let Some ( page_def) = & mut section. page_def {
1089+ let header = crate :: model:: header_footer:: HeaderFooter {
1090+ text : text. to_string ( ) ,
1091+ page_number_format : format as u8 ,
1092+ ..Default :: default ( )
1093+ } ;
1094+ page_def. header_footer . add_header ( header) ;
1095+ }
1096+ }
1097+ }
1098+ }
1099+
1100+ /// Add header with options (text + format)
1101+ pub fn add_header_with_options (
1102+ & mut self ,
1103+ text : & str ,
1104+ format : crate :: model:: PageNumberFormat ,
1105+ ) {
1106+ self . add_header_with_page_number ( text, format) ;
1107+ }
1108+
1109+ /// Add footer with options (text + format)
1110+ pub fn add_footer_with_options (
1111+ & mut self ,
1112+ text : & str ,
1113+ format : crate :: model:: PageNumberFormat ,
1114+ ) {
1115+ self . add_footer_with_page_number ( text, format) ;
1116+ }
1117+
1118+ /// Add a styled paragraph with predefined styles
1119+ pub fn add_styled_paragraph ( & mut self , text : & str , style_name : & str ) -> Result < ( ) > {
1120+ let style = match style_name. to_lowercase ( ) . as_str ( ) {
1121+ "heading1" | "h1" => style:: TextStyle {
1122+ bold : true ,
1123+ font_size : Some ( 20 ) ,
1124+ ..Default :: default ( )
1125+ } ,
1126+ "heading2" | "h2" => style:: TextStyle {
1127+ bold : true ,
1128+ font_size : Some ( 16 ) ,
1129+ ..Default :: default ( )
1130+ } ,
1131+ "heading3" | "h3" => style:: TextStyle {
1132+ bold : true ,
1133+ font_size : Some ( 14 ) ,
1134+ ..Default :: default ( )
1135+ } ,
1136+ "bold" => style:: TextStyle {
1137+ bold : true ,
1138+ ..Default :: default ( )
1139+ } ,
1140+ "italic" => style:: TextStyle {
1141+ italic : true ,
1142+ ..Default :: default ( )
1143+ } ,
1144+ "highlight" => style:: TextStyle {
1145+ background_color : Some ( 0xFFFF00 ) , // Yellow
1146+ ..Default :: default ( )
1147+ } ,
1148+ _ => Default :: default ( ) ,
1149+ } ;
1150+ self . add_paragraph_with_style ( text, & style)
1151+ }
1152+
1153+ /// Add paragraph with bold text
1154+ pub fn add_paragraph_with_bold ( & mut self , text : & str ) -> Result < ( ) > {
1155+ self . add_styled_paragraph ( text, "bold" )
1156+ }
1157+
1158+ /// Add paragraph with colors
1159+ pub fn add_paragraph_with_colors (
1160+ & mut self ,
1161+ text : & str ,
1162+ text_color : u32 ,
1163+ bg_color : u32 ,
1164+ ) -> Result < ( ) > {
1165+ let style = style:: TextStyle {
1166+ color : text_color,
1167+ background_color : Some ( bg_color) ,
1168+ ..Default :: default ( )
1169+ } ;
1170+ self . add_paragraph_with_style ( text, & style)
1171+ }
1172+
1173+ /// Add paragraph with highlight
1174+ pub fn add_paragraph_with_highlight ( & mut self , text : & str , color : u32 ) -> Result < ( ) > {
1175+ let style = style:: TextStyle {
1176+ background_color : Some ( color) ,
1177+ ..Default :: default ( )
1178+ } ;
1179+ self . add_paragraph_with_style ( text, & style)
1180+ }
1181+
1182+ /// Add mixed text with different styles (simplified version)
1183+ pub fn add_mixed_text ( & mut self , parts : & [ ( & str , Option < style:: TextStyle > ) ] ) -> Result < ( ) > {
1184+ // For now, just combine all text parts
1185+ let combined_text: String = parts. iter ( ) . map ( |( text, _) | * text) . collect ( ) ;
1186+ self . add_paragraph ( & combined_text)
1187+ }
1188+
1189+ /// Add a text box
1190+ pub fn add_text_box ( & mut self , text : & str ) -> Result < ( ) > {
1191+ self . add_text_box_at_position ( text, 10 , 10 , 50 , 20 )
1192+ }
1193+
1194+ /// Add a text box at specific position
1195+ pub fn add_text_box_at_position (
1196+ & mut self ,
1197+ text : & str ,
1198+ x_mm : u32 ,
1199+ y_mm : u32 ,
1200+ width_mm : u32 ,
1201+ height_mm : u32 ,
1202+ ) -> Result < ( ) > {
1203+ let text_box = crate :: model:: text_box:: TextBox {
1204+ text : text. to_string ( ) ,
1205+ x : ( x_mm * 100 ) as i32 , // Convert mm to HWPU
1206+ y : ( y_mm * 100 ) as i32 ,
1207+ width : width_mm * 100 ,
1208+ height : height_mm * 100 ,
1209+ ..Default :: default ( )
1210+ } ;
1211+
1212+ self . add_text_box_data ( text_box)
1213+ }
1214+
1215+ /// Add a styled text box
1216+ pub fn add_styled_text_box ( & mut self , text : & str , style_name : & str ) -> Result < ( ) > {
1217+ let ( border_color, bg_color) = match style_name. to_lowercase ( ) . as_str ( ) {
1218+ "highlight" => ( 0xFFFF00 , 0xFFFFCC ) ,
1219+ "info" => ( 0x0000FF , 0xE0E0FF ) ,
1220+ "warning" => ( 0xFF8800 , 0xFFEECC ) ,
1221+ "error" => ( 0xFF0000 , 0xFFCCCC ) ,
1222+ _ => ( 0x000000 , 0xFFFFFF ) ,
1223+ } ;
1224+
1225+ let text_box = crate :: model:: text_box:: TextBox {
1226+ text : text. to_string ( ) ,
1227+ x : 1000 ,
1228+ y : 1000 ,
1229+ width : 5000 ,
1230+ height : 2000 ,
1231+ border_color,
1232+ background_color : bg_color,
1233+ ..Default :: default ( )
1234+ } ;
1235+
1236+ self . add_text_box_data ( text_box)
1237+ }
1238+
1239+ /// Add custom text box
1240+ #[ allow( clippy:: too_many_arguments) ]
1241+ pub fn add_custom_text_box (
1242+ & mut self ,
1243+ text : & str ,
1244+ x_mm : u32 ,
1245+ y_mm : u32 ,
1246+ width_mm : u32 ,
1247+ height_mm : u32 ,
1248+ _alignment : crate :: model:: text_box:: TextBoxAlignment ,
1249+ _border_style : crate :: model:: text_box:: TextBoxBorderStyle ,
1250+ border_color : u32 ,
1251+ bg_color : u32 ,
1252+ ) -> Result < ( ) > {
1253+ let text_box = crate :: model:: text_box:: TextBox {
1254+ text : text. to_string ( ) ,
1255+ x : ( x_mm * 100 ) as i32 ,
1256+ y : ( y_mm * 100 ) as i32 ,
1257+ width : width_mm * 100 ,
1258+ height : height_mm * 100 ,
1259+ border_color,
1260+ background_color : bg_color,
1261+ ..Default :: default ( )
1262+ } ;
1263+
1264+ self . add_text_box_data ( text_box)
1265+ }
1266+
1267+ /// Add floating text box
1268+ pub fn add_floating_text_box (
1269+ & mut self ,
1270+ text : & str ,
1271+ x_mm : u32 ,
1272+ y_mm : u32 ,
1273+ width_mm : u32 ,
1274+ height_mm : u32 ,
1275+ ) -> Result < ( ) > {
1276+ self . add_text_box_at_position ( text, x_mm, y_mm, width_mm, height_mm)
1277+ }
1278+
1279+ /// Internal helper to add text box data to paragraph
1280+ fn add_text_box_data ( & mut self , text_box : crate :: model:: text_box:: TextBox ) -> Result < ( ) > {
1281+ use crate :: model:: paragraph:: Paragraph ;
1282+
1283+ if let Some ( body_text) = self . document . body_texts . get_mut ( self . current_section_idx ) {
1284+ if let Some ( section) = body_text. sections . get_mut ( 0 ) {
1285+ let mut paragraph = Paragraph :: default ( ) ;
1286+ paragraph. text_box_data = Some ( text_box) ;
1287+ paragraph. control_mask = 1 ; // Indicate control is present
1288+ section. paragraphs . push ( paragraph) ;
1289+ }
1290+ }
1291+
1292+ Ok ( ( ) )
1293+ }
10291294}
10301295
10311296impl Default for HwpWriter {
0 commit comments