Almost there.
[EDIT - removed a blow-by-blow debugging session]

... I figured it out!
Here's the missing manual, or at least missing example.

The mini-tute in http://drupal.org/node/218960#comment-811545 was pretty much the process I could figure out from the code.
BUT
that involves putting my stuff in the module folder. Looking at both the code and the API docs there seems to be an extremely robust plugin loader available...
but huh? it's not doing drupal hooks like normal.

Eventually I traced the plugin loader and related funcs : HOOK_panels_include_directory() enough to get it all into a contrib. Here's a delibrately simple custom renderer. Use it as a package to build on to make your own selectable styles..

Note this is deliberately not as clever as the distro ones - but is maybe a bit more hands-on and obvious.

For easy reference, I'll paste it in here directly:
boxer.module

/**
 * @file
 * 
 * This is a DEMONSTRATION file to assist learning how to make your own panel
 * styles. It doesn't add a lot of functionality, in fact it took 'rounded
 * corners and removed most of the magic. But it DOES show the hook names - and
 * more importantly the bits that needed to be added to your own panels plugin
 * module.
 * 
 * This utility basically only adds a 'style' selector to your panels admin,
 * which adds a css class to the element. BUT from this code you now have full
 * access to all the HTML and CSS relevant.
 * 
 * This example only does render_panel (not render_pane) but you can copy the
 * bits from panels/styles/block.inc if you want.
 * 
 * Take it from there.
 * 
 * @author dman coders.co.nz
 */

/**
 * Include a theme tweak for panels
 * 
 * Panels does a lot of magic loading, it does NOT use normal
 * module_implements() to load its hooks, so we have to do this:
 * 
 * @see HOOK_panels_include_directory()
 * @see http://doxy.samboyer.org/panels2/group__HookInvokers.html
 */
function boxer_panels_include_directory($plugintype) {
  if($plugintype == 'styles') {
    return 'panels_inc/' .$plugintype;
  }
}

/**
 * NEED to declare the theme names and the include files.
 * 
 * Or nothing works! Remember to flush the cache when you change this.
 * 
 * @see HOOK_theme()
 */
function boxer_theme() {
  $theme = array();
  $theme['boxer_boxed_corners_style_render_panel'] = array(
    'arguments' => array('content' => NULL, 'pane' => NULL, 'display' => NULL),
    'path' => 'panels_inc/styles/boxed_corners.inc',
    
  );
  return $theme;
}

boxer/panels_inc/styles/boxed_corners.inc

// $Id:  $

/**
 * @file styles/boxed_corners.inc
 * Definition of the 'boxed_corners' panel style.
 * 
 * Based  on rounded_corner.inc from panels.module
 * 
 * BUT MUCH DUMBED DOWN so you can see the important bits, not the clever bits.
 *
 * @author dman coders.co.nz 
 */

// ---------------------------------------------------------------------------
// Panels hooks.

/**
 * Implementation of HOOK_STYLENAME_panels_styles().
 * 
 * Where HOOK is the modulename as normal, and STYLENAME matches this inc
 * filename.
 */
function boxer_boxed_corners_panels_styles() {
  return array(
    'boxed_corners' => array(
      'title' => t('Boxed corners'),
      'description' => t('Presents the panes or panels with a folded corner box around them'),
      'render panel' => 'boxer_boxed_corners_style_render_panel',
      'settings form' => 'boxer_boxed_corners_style_settings_form',
    ),
  );
}

// ---------------------------------------------------------------------------
// Panels style plugin callbacks.

/**
 * Render callback.
 * 
 * Declared by name in the HOOK_panels_style() above.
 *
 * @ingroup themeable
 */
function theme_boxer_boxed_corners_style_render_panel($display, $panel_id, $panes, $settings) {
  $output = '';
  foreach ($panes as $pane_id => $pane) {
    $text = panels_render_pane($pane, $display->content[$pane_id], $display);
    if ($text) {
      $output .= boxer_boxed_corners_box($text);
    }
  }
  boxer_add_boxed_corners_css($display);
  return $output;
}

/**
 * Generates the CSS and adds it to the current page head.
 *
 * Note this does NOT do anything that cannot already be done with CSS! It's
 * here to show what COULD be done if you wanted to mess around.
 * 
 * For something this trivial, you may as well add a normal css file BUT you can
 * also do contextual or code things by writing it dynamically.
 *
 * @param $display
 *   A Panels display object.
 */
function boxer_add_boxed_corners_css($display) {
  static $displays_used = array();
  if (empty($displays_used[$display->css_id])) {
    $idstr = empty($display->css_id) ? '.boxed-corner' : "#$display->css_id";
    $url = url( drupal_get_path('module', 'boxer') . '/images', array('absolute' => TRUE));
  
    #######################################
    $css = <<<EOF
  
      $idstr {
        padding-bottom:6px;
      }
      $idstr .boxed-corner-inner {
        border-left:1px solid #DDDDDD;
        border-top:1px solid #DDDDDD;
        background:transparent url($url/block-right-bottom-bg.gif) no-repeat scroll right bottom;
        overflow:hidden;
        padding:5px 5px 10px;
      }
  
EOF;
    #######################################
  
    drupal_set_html_head("<style type=\"text/css\" media=\"all\">\n$css</style>\n");
    $displays_used[$display->css_id] = TRUE;
  }
}

/**
 * Settings form callback.
 * 
 * Example stub function only
 * 
 * See the panels.module distribution for panels with extra settings.
 * 
 */
function boxer_boxed_corners_style_settings_form($style_settings) {
  $form['info'] = array(
    '#type' => 'markup',
    '#value' => t('No settings'),
  );
  return $form;
}



/**
 * Create the HTML for our boxed corner box.
 * 
 * This doesn't add much to the normal rendering. But you can mess with it now.
 *
 * @param $text
 *   The content of this rounded corner box.
 *
 * @return
 *   The created HTML.
 */
function boxer_boxed_corners_box($content) {
  #######################################
  return <<<EOF
  <div class="boxed-corner">
    <div class="boxed-corner-top"></div>
    <div class="boxed-corner-inner">
          $content
    </div>
    <div class="boxed-corner-bottom"></div>
  </div>
EOF;
  #######################################
}
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Michelle’s picture

This looks very helpful. I've never tried making my own style and it's nice to have a simple example to work from.

Thanks,

Michelle

merlinofchaos’s picture

Status: Needs review » Needs work

This needs to be updated for the ctools integration for this to be useful.

mclin’s picture

Version: 6.x-3.0-alpha4 » 6.x-3.0-beta2

No matter what I do, I can't seem to get my style to show up in 'Pane style for "x"' dialog...

I even tried copying panels/plugins/styles/default.inc to default2.inc and putting a 2 after everything and still nothing show up.

I wonder if this has anything to do with this ctools integration you speak of.

merlinofchaos’s picture

You must implement hook_ctools_plugin_directories() so that CTools knows what directories to search. That would be the first thing to check.

H3x’s picture

Sorry to be a nag, but how exactly would one implement hook_ctools_plugin_directories()? I apologize for my low-level php knowledge, but this feature would really add a lot of functionality to Panels.

mclin’s picture

For just copying default.inc to get a new style, I discovered that while the new style wasn't showing up in the pane style dialog, it was showing up in region style. Good enough for me! Thanks for the reply.

CarbonPig’s picture

subscribe

rfay’s picture

Subscribing

webthingee’s picture

Subscribing

webthingee’s picture

A Themer's Solution....

I have in my theme a directory called plugins.
in there I have layouts and styles
in styles I have a folder called thintop
and... in there I have 2 files (tho I have commented out the template file in favor of this fancy rendering which gives me admin links and extra stuff in my pane...
thintop.inc and THEME-NAME-thintop.tpl.php
(based on http://drupal.org/node/495654)

The .inc looks like this

/**
 * @file 
 * Definition of the 'thintop' panel style.
 */

// ---------------------------------------------------------------------------
// Panels hooks.

/**
 * Implementation of hook_panels_style_info().
 */

function THEME_NAME_thintop_panels_styles() {
  return array(
    'thintop' => array(
      'title' => t('Thin Top'),
      'description' => t('Thin Top'),
      'render panel' => 'THEME_NAME_thintop_style_render_panel',
      'render pane' => 'THEME_NAME_thintop_style_render_pane',
      'settings form' => 'THEME_NAME_thintop_style_settings_form',
      'hook theme' => array(
        'THEME_NAME_thintop_box' => array(
          'arguments' => array('content' => NULL),
          'path' => panels_get_path('plugins/styles/thintop'),
          'template' => 'genesis-aii-thintop-box',
        ),
      ),
    ),
  );
}

// ---------------------------------------------------------------------------
// Panels style plugin callbacks.

/**
 * Render callback.
 *
 * @ingroup themeable
 */
function theme_THEME_NAME_thintop_style_render_pane($content, $pane, $display) {
  if (!empty($content->content)) {
    $idstr = $classstr = '';
    if (!empty($content->css_id)) {
      $idstr = ' id="' . $content->css_id . '"';
    }
    if (!empty($content->css_class)) {
      $classstr = ' ' . $content->css_class;
    }

    $output = "<div class=\"thintop panel-pane$classstr\"$idstr>\n";
    if (user_access('view pane admin links') && !empty($content->admin_links)) {
      $output .= "<div class=\"admin-links panel-hide\">" . theme('links', $content->admin_links) . "</div>\n";
    }
    if (!empty($content->title)) {
      // !Changed H2 tag to an H1 tag
      $output .= "<h3 class=\"pane-title\">$content->title</h3>\n";
    }

    if (!empty($content->feeds)) {
      $output .= "<div class=\"feed\">" . implode(' ', $content->feeds) . "</div>\n";
    }

    $output .= "<div class=\"pane-content\">$content->content</div>\n";

    if (!empty($content->links)) {
      $output .= "<div class=\"links\">" . theme('links', $content->links) . "</div>\n";
    }


    if (!empty($content->more)) {
      if (empty($content->more['title'])) {
        $content->more['title'] = t('more');
      }
      $output .= "<div class=\"more-link\">" . l($content->more['title'], $content->more['href']) . "</div>\n";
    }

    $output .= "</div>\n";
    return $output;
  }
}

when I was using a template the $output was

  $output .= '<h3 class="pane-title-thintop">';
  $output .= $content->title;
  $output .= '</h3>';
  $output .= $content->content;
  $output = theme('THEME_NAME_thintop_box', $output);
  return $output;

and the tpl.php is pretty basic

<div class="panel-pane thintop">
	<?php print $content; ?>
</div>


IMPORTANT!!!

Add to your .info file in your theme!!

;----------// Plugin Panels
	plugins[panels][layouts] = plugins/layouts
	plugins[panels][styles] = plugins/styles

remember to clear the theme registry

rfay’s picture

Issue tags: +rfaynovember

Putting this on the priority list for November. @webthingee or I will try to make it happen.

perhenrik’s picture

Subscribe (and yes, im looking for a good howto or bp on how to add styles...)

amcc’s picture

If you want to add a style in your theme rather than as a module I've written a tutorial here:
http://01am.co.uk/blog/creating-style-plugins-panels-your-theme-folder

let me know if you need more info

rfay’s picture

Status: Needs work » Needs review
FileSize
7.25 KB

Attached is a "panels plugin example" module intended to be placed in a subdirectory of the panels project. Better yet, it could go into panels/examples/panels_plugin_example. I imagine we'll have other modules in there someday.

This example shows how to use style and layout plugins, explains the path and filenaming conventions, and provides advanced help.

Let me know how you like it.

Thanks very much for the excellent references from #13:
Creating a Panels style plugin
and
Creating a Panels plugin in the theming layer.

Thanks,
-Randy

rfay’s picture

montesde’s picture

How would you use this to theme a form when using panels to override an add/edit page? I can get the plugin to work but i'm not exactly sure how to get it to understand the $form variables. I'm trying to use a tpl.php file. I think it has to do with my output function in my .inc file.

Anyone have any insight?

cap60552’s picture

Is there a separate callback for a settings form for an individual pane?
'settings form' seem to only be triggered when the default, or individual region settings are diplayed, but not individual panes setting.

I would like to be able to present a form field, or radio buttons (haven't yet decided) to allow the designer to specify an icon that would appear next to the title of the pane. So far I have only been able to get this to appear in all panes in a region instead of a single individual pane.

Any ideas?

merlinofchaos’s picture

'pane settings form'

cap60552’s picture

Thanks merlin, that was exactly what i was looking for!

bachbach’s picture

Issue tags: -rfaynovember +skinr

thanks for this tuto,
does anyone can help me on adding the skinr form to a custom plugin style pane settings ?

bachbach’s picture

Issue tags: -skinr +rfaynovember

oups sorry i changed the tags

DamienMcKenna’s picture

vijaycs85’s picture

Status: Needs review » Closed (won't fix)

As far as I understand the issue summary, this issue is trying to add an example module to explain something in panels module? If so, please move this issue toExamples Module.