Index: modules/field_ui/field_ui.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/field_ui/field_ui.admin.inc,v
retrieving revision 1.51
diff -u -p -r1.51 field_ui.admin.inc
--- modules/field_ui/field_ui.admin.inc	23 May 2010 19:10:23 -0000	1.51
+++ modules/field_ui/field_ui.admin.inc	24 May 2010 15:44:29 -0000
@@ -632,7 +632,104 @@ function field_ui_display_overview_form(
       '#type' => 'select',
       '#options' => $formatter_options,
       '#default_value' => $display['type'],
-    );
+      // @todo Not triggered when dragging back from 'Hidden'.
+      '#ajax' => array(
+        'callback' => 'field_ui_formatter_settings_js',
+        'wrapper' => 'field-display-overview',
+        'effect' => 'fade',
+      ),
+      '#field_name' => $name,
+    );
+
+    // Formatter settings.
+
+    // Check the currently selected formatter, and merge persisted values.
+    if (isset($form_state['values']['settings'][$name]['type'])) {
+      $formatter_type = $form_state['values']['settings'][$name]['type'];
+    }
+    else {
+      $formatter_type = $display['type'];
+    }
+    if (isset($form_state['field_ui_formatter_settings'][$name])) {
+      $settings = $form_state['field_ui_formatter_settings'][$name];
+    }
+    else {
+      $settings = $display['settings'];
+    }
+    $settings += field_info_formatter_settings($formatter_type);
+
+    $instance['display'][$view_mode]['type'] = $formatter_type;
+    $formatter = field_info_formatter_types($formatter_type);
+    $instance['display'][$view_mode]['module'] = $formatter['module'];
+    $instance['display'][$view_mode]['settings'] = $settings;
+
+    $table[$name]['settings_wrapper'] = array(
+      '#type' => 'container',
+      '#id' => 'field-formatter-settings-wrapper-' . $name,
+      '#attributes' => array('class' => array('field-formatter-settings-wrapper')),
+    );
+    $form[$name]['settings_wrapper']['actions'] = array('#type' => 'actions');
+
+    // Base button element for the various formatter settings actions.
+    $base_button = array(
+      '#type' => 'submit',
+      '#submit' => array('field_ui_formatter_settings_submit'),
+      '#ajax' => array(
+        'callback' => 'field_ui_formatter_settings_js',
+        'wrapper' => 'field-display-overview',
+        'effect' => 'fade',
+      ),
+      '#field_name' => $name,
+    );
+    $button_names = array(
+      'edit' => $name . '_formatter_settings_edit',
+      'save' => $name . '_formatter_settings_save',
+      'cancel' => $name . '_formatter_settings_cancel',
+    );
+
+    if (isset($form_state['field_ui_formatter_settings_edit']) && $form_state['field_ui_formatter_settings_edit'] == $name) {
+      // We are currently editing this field's formatter settings. Display
+      // the settings form, and submit buttons.
+      $additions = module_invoke($formatter['module'], 'field_formatter_settings_form', $field, $instance, $view_mode);
+      if (is_array($additions)) {
+        $table[$name]['settings_wrapper']['settings'] = $additions;
+      }
+      $table[$name]['settings_wrapper']['actions']['save_settings'] = $base_button + array(
+        '#type' => 'submit',
+        '#name' => $button_names['save'],
+        '#value' => t('Save'),
+        '#attributes' => array('class' => array('field-formatter-settings-save')),
+        '#op' => 'save',
+      );
+      $table[$name]['settings_wrapper']['actions']['cancel_settings'] = $base_button + array(
+        '#name' => $button_names['cancel'],
+        '#value' => t('Cancel'),
+        '#attributes' => array('class' => array('field-formatter-settings-cancel')),
+        '#op' => 'cancel',
+        // Do not check errors for the 'Cancel' button.
+        '#limit_validation_errors' => array(),
+      );
+      $table[$name]['type']['#ajax'] += array(
+        'trigger_as' => array('name' => $button_names['cancel']),
+      );
+    }
+    else {
+      // Display a summary of the current formatter settings.
+      $summary = module_invoke($formatter['module'], 'field_formatter_settings_summary', $field, $instance, $view_mode);
+      if ($summary) {
+        $table[$name]['settings_wrapper']['summary'] = array(
+          '#markup' => $summary,
+        );
+        $table[$name]['settings_wrapper']['actions']['settings_edit'] = $base_button + array(
+          '#name' => $button_names['edit'],
+          '#value' => t('Settings'),
+          '#attributes' => array('class' => array('field-formatter-settings-edit')),
+          '#op' => 'edit',
+          // Do not check errors for the 'Edit' button.
+          '#limit_validation_errors' => array(),
+        );
+      }
+    }
     $table['#field_rows'][] = $name;
 
     // Collect default formatters for the JS script.
@@ -703,6 +800,50 @@ function field_ui_display_overview_form(
   return $form;
 }
 
+
+/**
+ * @todo
+ */
+function field_ui_formatter_settings_submit($form, &$form_state) {
+  $trigger = $form_state['triggering_element'];
+  $field_name = $trigger['#field_name'];
+  $op = $trigger['#op'];
+
+  switch ($op) {
+    case 'edit':
+      // Store the field whose settings are currently being edited.
+      $form_state['field_ui_formatter_settings_edit'] = $field_name;
+      break;
+
+    case 'save':
+      // Store the saved settings.
+      $values = $form_state['values']['settings'][$field_name]['settings_wrapper']['settings'];
+      $form_state['field_ui_formatter_settings'][$field_name] = $values;
+      // Fall-through to the 'cancel' case.
+    case 'cancel':
+      // Unset the field as being currently edited.
+      unset($form_state['field_ui_formatter_settings_edit']);
+      break;
+  }
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * @todo
+ */
+function field_ui_formatter_settings_js($form, &$form_state) {
+  $trigger = $form_state['triggering_element'];
+  $field_name = $trigger['#field_name'];
+
+  $element = &$form['settings'][$field_name]['settings_wrapper'];
+  // Add a DIV to receive the AJAX effect.
+  $element['#prefix'] = '<div class="ajax-new-content">' . (isset($element['#prefix']) ? $element['#prefix'] : '');
+  $element['#suffix'] = (isset($element['#suffix']) ? $element['#suffix'] : '') . '</div>';
+
+  return $form['settings'];
+}
+
 /**
  * Theme preprocess function for field_ui-display-overview-table.tpl.php.
  */
@@ -731,14 +872,7 @@ function template_preprocess_field_ui_di
 
       $row = new stdClass();
       foreach (element_children($element) as $child) {
-        if (array_key_exists('label', $element[$child])) {
-          $row->{$child} = new stdClass();
-          $row->{$child}->label = drupal_render($element[$child]['label']);
-          $row->{$child}->type = drupal_render($element[$child]['type']);
-        }
-        else {
-          $row->{$child} = drupal_render($element[$child]);
-        }
+        $row->{$child} = drupal_render($element[$child]);
       }
       $row->class = 'draggable';
       $row->label_class = 'label-field';
@@ -761,7 +895,26 @@ function field_ui_display_overview_form_
   // Save data for 'regular' fields.
   foreach ($form['#fields'] as $field_name) {
     $instance = field_info_instance($entity_type, $field_name, $bundle);
-    $instance['display'][$view_mode] = $form_values['settings'][$field_name];
+    $values = $form_values['settings'][$field_name];
+    // Get formatter settings. They lie either directly in submitted form
+    // values (if the whole form was submitted while some formatter
+    // settings were being edited), or have been persisted in
+    // $form_state.
+    $settings = $instance['display'][$view_mode]['settings'];
+    if (isset($values['settings_wrapper']['settings'])) {
+      $settings = $values['settings_wrapper']['settings'];
+    }
+    elseif (isset($form_state['field_ui_formatter_settings'][$field_name])) {
+      // @todo Should we check formatters are consistent ?
+      $settings = $form_state['field_ui_formatter_settings'][$field_name];
+    }
+
+    $instance['display'][$view_mode] = array(
+      'label' => $values['label'],
+      'type' => $values['type'],
+      'weight' => $values['weight'],
+      'settings' => $settings,
+    );
     field_update_instance($instance);
   }
 
Index: modules/field_ui/field_ui.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/field_ui/field_ui.api.php,v
retrieving revision 1.6
diff -u -p -r1.6 field_ui.api.php
--- modules/field_ui/field_ui.api.php	4 May 2010 16:11:08 -0000	1.6
+++ modules/field_ui/field_ui.api.php	24 May 2010 15:44:29 -0000
@@ -131,6 +131,67 @@ function hook_field_widget_settings_form
   return $form;
 }
 
+
+/**
+ * Add settings to a formatter settings form.
+ *
+ * @todo Invoked from field_ui_field_edit_form() to allow the module defining the
+ * formatter to add settings.
+ *
+ * @param $field
+ *   The field structure being configured.
+ * @param $instance
+ *   The instance structure being configured.
+ *
+ * @return
+ *   The form definition for the formatter settings.
+ */
+function hook_field_formatter_settings_form($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $form = array();
+
+  if ($display['type'] == 'text_trimmed' || $display['type'] == 'text_summary_or_trimmed') {
+    $form['trim_length'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Length'),
+      '#default_value' => $settings['trim_length'],
+      '#element_validate' => array('_element_validate_integer_positive'),
+      '#required' => TRUE,
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Provide a short summary for the current formatter settings of an instance.
+ *
+ * @todo Invoked from field_ui_field_edit_form() to allow the module defining the
+ * formatter to add settings.
+ *
+ * @param $field
+ *   The field structure being configured.
+ * @param $instance
+ *   The instance structure being configured.
+ *
+ * @return
+ *   A string containing a short summary of the formatter settings.
+ */
+function hook_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = '';
+
+  if ($display['type'] == 'text_trimmed' || $display['type'] == 'text_summary_or_trimmed') {
+    $summary = t('Length: @chars chars', array('@chars' => $settings['trim_length']));
+  }
+
+  return $summary;
+}
+
 /**
  * Provide information on view mode tabs for an entity type.
  *
Index: modules/field_ui/field_ui-display-overview-table.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/field_ui/field_ui-display-overview-table.tpl.php,v
retrieving revision 1.1
diff -u -p -r1.1 field_ui-display-overview-table.tpl.php
--- modules/field_ui/field_ui-display-overview-table.tpl.php	24 May 2010 04:46:43 -0000	1.1
+++ modules/field_ui/field_ui-display-overview-table.tpl.php	24 May 2010 15:44:29 -0000
@@ -36,7 +36,7 @@
           <td><span class="<?php print $row->label_class; ?>"><?php print $row->human_name; ?></span></td>
           <td><?php print $row->weight . $row->hidden_name; ?></td>
           <td><?php if (isset($row->label)) print $row->label; ?></td>
-          <td><?php print $row->type; ?></td>
+          <td><?php print $row->type; print $row->settings_wrapper; ?></td>
         </tr>
         <?php $count++;
       endforeach; ?>
@@ -51,10 +51,10 @@
           <td><span class="<?php print $row->label_class; ?>"><?php print $row->human_name; ?></span></td>
           <td><?php print $row->weight . $row->hidden_name; ?></td>
           <td><?php if (isset($row->label)) print $row->label; ?></td>
-          <td><?php print $row->type; ?></td>
+          <td><?php print $row->type; print $row->settings_wrapper; ?></td>
         </tr>
         <?php $count++;
       endforeach; ?>
     </tbody>
   </table>
-<?php endif; ?>
+<?php endif; ?>
Index: modules/image/image.field.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/image/image.field.inc,v
retrieving revision 1.21
diff -u -p -r1.21 image.field.inc
--- modules/image/image.field.inc	30 Apr 2010 12:53:47 -0000	1.21
+++ modules/image/image.field.inc	24 May 2010 15:44:29 -0000
@@ -428,14 +428,17 @@ function image_field_formatter_info() {
     'image' => array(
       'label' => t('Image'),
       'field types' => array('image'),
+      'settings' => array('foo' => 1),
     ),
     'image_link_content' => array(
       'label' => t('Image linked to content'),
       'field types' => array('image'),
+      'settings' => array('foo' => 1),
     ),
     'image_link_file' => array(
       'label' => t('Image linked to file'),
       'field types' => array('image'),
+      'settings' => array('foo' => 1),
     ),
   );
 
@@ -443,14 +446,17 @@ function image_field_formatter_info() {
     $formatters['image__' . $style['name']] = array(
       'label' => t('Image "@style"', array('@style' => $style['name'])),
       'field types' => array('image'),
+      'settings' => array('foo' => 1),
     );
     $formatters['image_link_content__' . $style['name']] = array(
       'label' => t('Image "@style" linked to content', array('@style' => $style['name'])),
       'field types' => array('image'),
+      'settings' => array('foo' => 1),
     );
     $formatters['image_link_file__' . $style['name']] = array(
       'label' => t('Image "@style" linked to file', array('@style' => $style['name'])),
       'field types' => array('image'),
+      'settings' => array('foo' => 1),
     );
   }
 
@@ -458,6 +464,39 @@ function image_field_formatter_info() {
 }
 
 /**
+ * Implements hook_field_formatter_settings_form().
+ */
+function image_field_formatter_settings_form($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $form = array();
+
+  $form['foo'] = array(
+    '#title' => t('foo'),
+    '#type' => 'textfield',
+    '#size' => 20,
+    '#default_value' => $settings['foo'],
+    '#element_validate' => array('_element_validate_integer_positive'),
+    '#required' => TRUE,
+  );
+
+  return $form;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function image_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = t('Foo: @foo', array('@foo' => $settings['foo']));
+
+  return $summary;
+}
+
+/**
  * Implements hook_field_formatter_view().
  */
 function image_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
Index: modules/field/modules/text/text.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.module,v
retrieving revision 1.54
diff -u -p -r1.54 text.module
--- modules/field/modules/text/text.module	6 May 2010 05:59:31 -0000	1.54
+++ modules/field/modules/text/text.module	24 May 2010 15:44:29 -0000
@@ -249,6 +249,7 @@ function text_field_formatter_info() {
     'text_trimmed' => array(
       'label' => t('Trimmed'),
       'field types' => array('text', 'text_long', 'text_with_summary'),
+      'settings' => array('trim_length' => 600),
     ),
 
     // The 'summary or trimmed' field formatter for text_with_summary
@@ -258,11 +259,51 @@ function text_field_formatter_info() {
     'text_summary_or_trimmed' => array(
       'label' => t('Summary or trimmed'),
       'field types' => array('text_with_summary'),
+      'settings' => array('trim_length' => 600),
     ),
   );
 }
 
 /**
+ * Implements hook_field_formatter_settings_form().
+ */
+function text_field_formatter_settings_form($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $form = array();
+
+  if ($display['type'] == 'text_trimmed' || $display['type'] == 'text_summary_or_trimmed') {
+    $form['trim_length'] = array(
+      '#title' => t('Length'),
+      '#type' => 'textfield',
+      '#size' => 20,
+      '#default_value' => $settings['trim_length'],
+      '#element_validate' => array('_element_validate_integer_positive'),
+      '#required' => TRUE,
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function text_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = '';
+
+  if ($display['type'] == 'text_trimmed' || $display['type'] == 'text_summary_or_trimmed') {
+    $summary = t('Length: @length characters', array('@length' => $settings['trim_length']));
+  }
+
+  return $summary;
+}
+
+/**
  * Implements hook_field_formatter_view().
  */
 function text_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
@@ -271,23 +312,30 @@ function text_field_formatter_view($enti
   switch ($display['type']) {
     case 'text_default':
     case 'text_trimmed':
+      $size = variable_get('teaser_length_' . $instance['bundle'], 600);
+      if (isset($display['settings']['trim_length'])) {
+        $size = $display['settings']['trim_length'];
+      }
       foreach ($items as $delta => $item) {
         $output = _text_sanitize($instance, $langcode, $item, 'value');
         if ($display['type'] == 'text_trimmed') {
-          $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL);
+          $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $size);
         }
         $element[$delta] = array('#markup' => $output);
       }
       break;
 
     case 'text_summary_or_trimmed':
+      $size = variable_get('teaser_length_' . $instance['bundle'], 600);
+      if (isset($display['settings']['trim_length'])) {
+        $size = $display['settings']['trim_length'];
+      }
       foreach ($items as $delta => $item) {
         if (!empty($item['summary'])) {
           $output = _text_sanitize($instance, $langcode, $item, 'summary');
         }
         else {
           $output = _text_sanitize($instance, $langcode, $item, 'value');
-          $size = variable_get('teaser_length_' . $instance['bundle'], 600);
           $output = text_summary($output, $instance['settings']['text_processing'] ? $item['format'] : NULL, $size);
         }
         $element[$delta] = array('#markup' => $output);
