Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/animation/anim_channels_defines.c
| Show First 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | static void acf_generic_root_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) | ||||
| short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; | short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; | ||||
| float color[3]; | float color[3]; | ||||
| /* set backdrop drawing color */ | /* set backdrop drawing color */ | ||||
| acf->get_backdrop_color(ac, ale, color); | acf->get_backdrop_color(ac, ale, color); | ||||
| glColor3fv(color); | glColor3fv(color); | ||||
| /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ | /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ | ||||
| uiSetRoundBox((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); | UI_draw_roundbox_corner_set((expanded) ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); | ||||
| uiDrawBox(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); | UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); | ||||
| } | } | ||||
| /* get backdrop color for data expanders under top-level Scene/Object */ | /* get backdrop color for data expanders under top-level Scene/Object */ | ||||
| static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) | static void acf_generic_dataexpand_color(bAnimContext *UNUSED(ac), bAnimListElem *UNUSED(ale), float r_color[3]) | ||||
| { | { | ||||
| /* lighter color than top-level widget */ | /* lighter color than top-level widget */ | ||||
| UI_GetThemeColor3fv(TH_DOPESHEET_CHANNELSUBOB, r_color); | UI_GetThemeColor3fv(TH_DOPESHEET_CHANNELSUBOB, r_color); | ||||
| ▲ Show 20 Lines • Show All 282 Lines • ▼ Show 20 Lines | static void acf_summary_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) | ||||
| /* set backdrop drawing color */ | /* set backdrop drawing color */ | ||||
| acf->get_backdrop_color(ac, ale, color); | acf->get_backdrop_color(ac, ale, color); | ||||
| glColor3fv(color); | glColor3fv(color); | ||||
| /* rounded corners on LHS only | /* rounded corners on LHS only | ||||
| * - top and bottom | * - top and bottom | ||||
| * - special hack: make the top a bit higher, since we are first... | * - special hack: make the top a bit higher, since we are first... | ||||
| */ | */ | ||||
| uiSetRoundBox(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); | UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); | ||||
| uiDrawBox(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); | UI_draw_roundbox_gl_mode(GL_POLYGON, 0, yminc - 2, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); | ||||
| } | } | ||||
| /* name for summary entries */ | /* name for summary entries */ | ||||
| static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name) | static void acf_summary_name(bAnimListElem *UNUSED(ale), char *name) | ||||
| { | { | ||||
| if (name) | if (name) | ||||
| BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE); | BLI_strncpy(name, IFACE_("Dope Sheet Summary"), ANIM_CHAN_NAME_SIZE); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 362 Lines • ▼ Show 20 Lines | static void acf_group_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) | ||||
| short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; | short offset = (acf->get_offset) ? acf->get_offset(ac, ale) : 0; | ||||
| float color[3]; | float color[3]; | ||||
| /* set backdrop drawing color */ | /* set backdrop drawing color */ | ||||
| acf->get_backdrop_color(ac, ale, color); | acf->get_backdrop_color(ac, ale, color); | ||||
| glColor3fv(color); | glColor3fv(color); | ||||
| /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ | /* rounded corners on LHS only - top only when expanded, but bottom too when collapsed */ | ||||
| uiSetRoundBox(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); | UI_draw_roundbox_corner_set(expanded ? UI_CNR_TOP_LEFT : (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)); | ||||
| uiDrawBox(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); | UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc, v2d->cur.xmax + EXTRA_SCROLL_PAD, ymaxc, 8); | ||||
| } | } | ||||
| /* name for group entries */ | /* name for group entries */ | ||||
| static void acf_group_name(bAnimListElem *ale, char *name) | static void acf_group_name(bAnimListElem *ale, char *name) | ||||
| { | { | ||||
| bActionGroup *agrp = (bActionGroup *)ale->data; | bActionGroup *agrp = (bActionGroup *)ale->data; | ||||
| /* just copy the name... */ | /* just copy the name... */ | ||||
| ▲ Show 20 Lines • Show All 2,192 Lines • ▼ Show 20 Lines | static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc) | ||||
| else { | else { | ||||
| float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; | float alpha = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f; | ||||
| glColor4f(color[0], color[1], color[2], alpha); | glColor4f(color[0], color[1], color[2], alpha); | ||||
| } | } | ||||
| /* only on top left corner, to show that this channel sits on top of the preceding ones | /* only on top left corner, to show that this channel sits on top of the preceding ones | ||||
| * while still linking into the action line strip to the right | * while still linking into the action line strip to the right | ||||
| */ | */ | ||||
| uiSetRoundBox(UI_CNR_TOP_LEFT); | UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT); | ||||
| /* draw slightly shifted up vertically to look like it has more separation from other channels, | /* draw slightly shifted up vertically to look like it has more separation from other channels, | ||||
| * but we then need to slightly shorten it so that it doesn't look like it overlaps | * but we then need to slightly shorten it so that it doesn't look like it overlaps | ||||
| */ | */ | ||||
| uiDrawBox(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8); | UI_draw_roundbox_gl_mode(GL_POLYGON, offset, yminc + NLACHANNEL_SKIP, (float)v2d->cur.xmax, ymaxc + NLACHANNEL_SKIP - 1, 8); | ||||
| } | } | ||||
| /* name for nla action entries */ | /* name for nla action entries */ | ||||
| static void acf_nlaaction_name(bAnimListElem *ale, char *name) | static void acf_nlaaction_name(bAnimListElem *ale, char *name) | ||||
| { | { | ||||
| bAction *act = (bAction *)ale->data; | bAction *act = (bAction *)ale->data; | ||||
| if (name) { | if (name) { | ||||
| ▲ Show 20 Lines • Show All 417 Lines • ▼ Show 20 Lines | if (selected) | ||||
| UI_ThemeColor(TH_TEXT_HI); | UI_ThemeColor(TH_TEXT_HI); | ||||
| else | else | ||||
| UI_ThemeColor(TH_TEXT); | UI_ThemeColor(TH_TEXT); | ||||
| /* get name */ | /* get name */ | ||||
| acf->name(ale, name); | acf->name(ale, name); | ||||
| offset += 3; | offset += 3; | ||||
| UI_DrawString(offset, ytext, name); | UI_draw_string(offset, ytext, name); | ||||
| /* draw red underline if channel is disabled */ | /* draw red underline if channel is disabled */ | ||||
| if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) { | if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) { | ||||
| /* FIXME: replace hardcoded color here, and check on extents! */ | /* FIXME: replace hardcoded color here, and check on extents! */ | ||||
| glColor3f(1.0f, 0.0f, 0.0f); | glColor3f(1.0f, 0.0f, 0.0f); | ||||
| glLineWidth(2.0); | glLineWidth(2.0); | ||||
| fdrawline((float)(offset), yminc, | fdrawline((float)(offset), yminc, | ||||
| (float)(v2d->cur.xmax), yminc); | (float)(v2d->cur.xmax), yminc); | ||||
| ▲ Show 20 Lines • Show All 322 Lines • ▼ Show 20 Lines | switch (setting) { | ||||
| default: | default: | ||||
| tooltip = NULL; | tooltip = NULL; | ||||
| icon = 0; | icon = 0; | ||||
| break; | break; | ||||
| } | } | ||||
| /* type of button */ | /* type of button */ | ||||
| if (negflag) | if (negflag) | ||||
| butType = ICONTOGN; | butType = UI_BTYPE_ICON_TOGGLE_N; | ||||
| else | else | ||||
| butType = ICONTOG; | butType = UI_BTYPE_ICON_TOGGLE; | ||||
| /* draw button for setting */ | /* draw button for setting */ | ||||
| if (ptr && flag) { | if (ptr && flag) { | ||||
| switch (ptrsize) { | switch (ptrsize) { | ||||
| case sizeof(int): /* integer pointer for setting */ | case sizeof(int): /* integer pointer for setting */ | ||||
| but = uiDefIconButBitI(block, butType, flag, 0, icon, | but = uiDefIconButBitI(block, butType, flag, 0, icon, | ||||
| xpos, ypos, ICON_WIDTH, ICON_WIDTH, ptr, 0, 0, 0, 0, tooltip); | xpos, ypos, ICON_WIDTH, ICON_WIDTH, ptr, 0, 0, 0, 0, tooltip); | ||||
| break; | break; | ||||
| Show All 12 Lines | if (ptr && flag) { | ||||
| /* set call to send relevant notifiers and/or perform type-specific updates */ | /* set call to send relevant notifiers and/or perform type-specific updates */ | ||||
| if (but) { | if (but) { | ||||
| switch (setting) { | switch (setting) { | ||||
| /* settings needing flushing up/down hierarchy */ | /* settings needing flushing up/down hierarchy */ | ||||
| case ACHANNEL_SETTING_VISIBLE: /* Graph Editor - 'visibility' toggles */ | case ACHANNEL_SETTING_VISIBLE: /* Graph Editor - 'visibility' toggles */ | ||||
| case ACHANNEL_SETTING_PROTECT: /* General - protection flags */ | case ACHANNEL_SETTING_PROTECT: /* General - protection flags */ | ||||
| case ACHANNEL_SETTING_MUTE: /* General - muting flags */ | case ACHANNEL_SETTING_MUTE: /* General - muting flags */ | ||||
| case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */ | case ACHANNEL_SETTING_PINNED: /* NLA Actions - 'map/nomap' */ | ||||
| uiButSetNFunc(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting)); | UI_but_funcN_set(but, achannel_setting_flush_widget_cb, MEM_dupallocN(ale), SET_INT_IN_POINTER(setting)); | ||||
| break; | break; | ||||
| /* settings needing special attention */ | /* settings needing special attention */ | ||||
| case ACHANNEL_SETTING_SOLO: /* NLA Tracks - Solo toggle */ | case ACHANNEL_SETTING_SOLO: /* NLA Tracks - Solo toggle */ | ||||
| uiButSetFunc(but, achannel_nlatrack_solo_widget_cb, ale->adt, ale->data); | UI_but_func_set(but, achannel_nlatrack_solo_widget_cb, ale->adt, ale->data); | ||||
| break; | break; | ||||
| /* no flushing */ | /* no flushing */ | ||||
| case ACHANNEL_SETTING_EXPAND: /* expanding - cannot flush, otherwise all would open/close at once */ | case ACHANNEL_SETTING_EXPAND: /* expanding - cannot flush, otherwise all would open/close at once */ | ||||
| default: | default: | ||||
| uiButSetFunc(but, achannel_setting_widget_cb, NULL, NULL); | UI_but_func_set(but, achannel_setting_widget_cb, NULL, NULL); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Draw UI widgets the given channel */ | /* Draw UI widgets the given channel */ | ||||
| void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index) | void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale, uiBlock *block, float yminc, float ymaxc, size_t channel_index) | ||||
| Show All 14 Lines | else | ||||
| offset = 0; | offset = 0; | ||||
| /* calculate appropriate y-coordinates for icon buttons | /* calculate appropriate y-coordinates for icon buttons | ||||
| */ | */ | ||||
| y = (ymaxc - yminc) / 2 + yminc; | y = (ymaxc - yminc) / 2 + yminc; | ||||
| ymid = y - 0.5f * ICON_WIDTH; | ymid = y - 0.5f * ICON_WIDTH; | ||||
| /* no button backdrop behind icons */ | /* no button backdrop behind icons */ | ||||
| uiBlockSetEmboss(block, UI_EMBOSSN); | UI_block_emboss_set(block, UI_EMBOSS_NONE); | ||||
| /* step 1) draw expand widget ....................................... */ | /* step 1) draw expand widget ....................................... */ | ||||
| if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) { | if (acf->has_setting(ac, ale, ACHANNEL_SETTING_EXPAND)) { | ||||
| draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_EXPAND); | draw_setting_widget(ac, ale, acf, block, offset, ymid, ACHANNEL_SETTING_EXPAND); | ||||
| offset += ICON_WIDTH; | offset += ICON_WIDTH; | ||||
| } | } | ||||
| /* step 2) draw icon ............................................... */ | /* step 2) draw icon ............................................... */ | ||||
| Show All 30 Lines | if (ac->ads->renameIndex == channel_index + 1) { | ||||
| /* draw renaming widget if we can get RNA pointer for it | /* draw renaming widget if we can get RNA pointer for it | ||||
| * NOTE: property may only be available in some cases, even if we have | * NOTE: property may only be available in some cases, even if we have | ||||
| * a callback available (e.g. broken F-Curve rename) | * a callback available (e.g. broken F-Curve rename) | ||||
| */ | */ | ||||
| if (acf->name_prop(ale, &ptr, &prop)) { | if (acf->name_prop(ale, &ptr, &prop)) { | ||||
| uiBut *but; | uiBut *but; | ||||
| uiBlockSetEmboss(block, UI_EMBOSS); | UI_block_emboss_set(block, UI_EMBOSS); | ||||
| but = uiDefButR(block, TEX, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height, | but = uiDefButR(block, UI_BTYPE_TEXT, 1, "", offset + 3, yminc, RENAME_TEXT_WIDTH, channel_height, | ||||
| &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL); | &ptr, RNA_property_identifier(prop), -1, 0, 0, -1, -1, NULL); | ||||
| uiButSetFunc(but, achannel_setting_rename_done_cb, ac->ads, NULL); | UI_but_func_set(but, achannel_setting_rename_done_cb, ac->ads, NULL); | ||||
| uiButActiveOnly(C, ac->ar, block, but); | UI_but_active_only(C, ac->ar, block, but); | ||||
| uiBlockSetEmboss(block, UI_EMBOSSN); | UI_block_emboss_set(block, UI_EMBOSS_NONE); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* step 5) draw mute+protection toggles + (sliders) ....................... */ | /* step 5) draw mute+protection toggles + (sliders) ....................... */ | ||||
| /* reset offset - now goes from RHS of panel */ | /* reset offset - now goes from RHS of panel */ | ||||
| offset = 0; | offset = 0; | ||||
| Show All 40 Lines | if (!(draw_sliders) || (BLI_rcti_size_x(&v2d->mask) > ACHANNEL_BUTTON_WIDTH / 2) ) { | ||||
| draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_PINNED); | draw_setting_widget(ac, ale, acf, block, (int)v2d->cur.xmax - offset, ymid, ACHANNEL_SETTING_PINNED); | ||||
| } | } | ||||
| /* NLA Action "pushdown" */ | /* NLA Action "pushdown" */ | ||||
| if ((ale->type == ANIMTYPE_NLAACTION) && (ale->adt && ale->adt->action) && !(ale->adt->flag & ADT_NLA_EDIT_ON)) { | if ((ale->type == ANIMTYPE_NLAACTION) && (ale->adt && ale->adt->action) && !(ale->adt->flag & ADT_NLA_EDIT_ON)) { | ||||
| uiBut *but; | uiBut *but; | ||||
| PointerRNA *opptr_b; | PointerRNA *opptr_b; | ||||
| uiBlockSetEmboss(block, UI_EMBOSS); | UI_block_emboss_set(block, UI_EMBOSS); | ||||
| offset += UI_UNIT_X; | offset += UI_UNIT_X; | ||||
| but = uiDefIconButO(block, BUT, "NLA_OT_action_pushdown", WM_OP_INVOKE_DEFAULT, ICON_NLA_PUSHDOWN, | but = uiDefIconButO(block, UI_BTYPE_BUT, "NLA_OT_action_pushdown", WM_OP_INVOKE_DEFAULT, ICON_NLA_PUSHDOWN, | ||||
| (int)v2d->cur.xmax - offset, ymid, UI_UNIT_X, UI_UNIT_X, NULL); | (int)v2d->cur.xmax - offset, ymid, UI_UNIT_X, UI_UNIT_X, NULL); | ||||
| opptr_b = uiButGetOperatorPtrRNA(but); | opptr_b = UI_but_operator_ptr_get(but); | ||||
| RNA_int_set(opptr_b, "channel_index", channel_index); | RNA_int_set(opptr_b, "channel_index", channel_index); | ||||
| uiBlockSetEmboss(block, UI_EMBOSSN); | UI_block_emboss_set(block, UI_EMBOSS_NONE); | ||||
| } | } | ||||
| } | } | ||||
| /* draw slider | /* draw slider | ||||
| * - even if we can draw sliders for this view, we must also check that the channel-type supports them | * - even if we can draw sliders for this view, we must also check that the channel-type supports them | ||||
| * (only only F-Curves really can support them for now) | * (only only F-Curves really can support them for now) | ||||
| * - to make things easier, we use RNA-autobuts for this so that changes are reflected immediately, | * - to make things easier, we use RNA-autobuts for this so that changes are reflected immediately, | ||||
| * wherever they occurred. BUT, we don't use the layout engine, otherwise we'd get wrong alignment, | * wherever they occurred. UI_BTYPE_BUT, we don't use the layout engine, otherwise we'd get wrong alignment, | ||||
| * and wouldn't be able to auto-keyframe... | * and wouldn't be able to auto-keyframe... | ||||
| * - slider should start before the toggles (if they're visible) to keep a clean line down the side | * - slider should start before the toggles (if they're visible) to keep a clean line down the side | ||||
| */ | */ | ||||
| if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) { | if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) { | ||||
| /* adjust offset */ | /* adjust offset */ | ||||
| // TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough | // TODO: make slider width dynamic, so that they can be easier to use when the view is wide enough | ||||
| offset += SLIDER_WIDTH; | offset += SLIDER_WIDTH; | ||||
| /* need backdrop behind sliders... */ | /* need backdrop behind sliders... */ | ||||
| uiBlockSetEmboss(block, UI_EMBOSS); | UI_block_emboss_set(block, UI_EMBOSS); | ||||
| if (ale->id) { /* Slider using RNA Access -------------------- */ | if (ale->id) { /* Slider using RNA Access -------------------- */ | ||||
| PointerRNA id_ptr, ptr; | PointerRNA id_ptr, ptr; | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| char *rna_path = NULL; | char *rna_path = NULL; | ||||
| int array_index = 0; | int array_index = 0; | ||||
| short free_path = 0; | short free_path = 0; | ||||
| Show All 21 Lines | if ((draw_sliders) && ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_SHAPEKEY)) { | ||||
| if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { | if (RNA_path_resolve_property(&id_ptr, rna_path, &ptr, &prop)) { | ||||
| uiBut *but; | uiBut *but; | ||||
| /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ | /* create the slider button, and assign relevant callback to ensure keyframes are inserted... */ | ||||
| but = uiDefAutoButR(block, &ptr, prop, array_index, "", ICON_NONE, (int)v2d->cur.xmax - offset, ymid, SLIDER_WIDTH, (int)ymaxc - yminc); | but = uiDefAutoButR(block, &ptr, prop, array_index, "", ICON_NONE, (int)v2d->cur.xmax - offset, ymid, SLIDER_WIDTH, (int)ymaxc - yminc); | ||||
| /* assign keyframing function according to slider type */ | /* assign keyframing function according to slider type */ | ||||
| if (ale->type == ANIMTYPE_SHAPEKEY) | if (ale->type == ANIMTYPE_SHAPEKEY) | ||||
| uiButSetFunc(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data); | UI_but_func_set(but, achannel_setting_slider_shapekey_cb, ale->id, ale->data); | ||||
| else | else | ||||
| uiButSetFunc(but, achannel_setting_slider_cb, ale->id, ale->data); | UI_but_func_set(but, achannel_setting_slider_cb, ale->id, ale->data); | ||||
| } | } | ||||
| /* free the path if necessary */ | /* free the path if necessary */ | ||||
| if (free_path) | if (free_path) | ||||
| MEM_freeN(rna_path); | MEM_freeN(rna_path); | ||||
| } | } | ||||
| } | } | ||||
| else { /* Special Slider for stuff without RNA Access ---------- */ | else { /* Special Slider for stuff without RNA Access ---------- */ | ||||
| // TODO: only implement this case when we really need it... | // TODO: only implement this case when we really need it... | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* *********************************************** */ | /* *********************************************** */ | ||||