Panda3D
 All Classes Functions Variables Enumerations
winStatsGraph.cxx
00001 // Filename: winStatsGraph.cxx
00002 // Created by:  drose (03Dec03)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "winStatsGraph.h"
00016 #include "winStatsMonitor.h"
00017 #include "winStatsLabelStack.h"
00018 
00019 bool WinStatsGraph::_graph_window_class_registered = false;
00020 const char * const WinStatsGraph::_graph_window_class_name = "graph";
00021 
00022 DWORD WinStatsGraph::graph_window_style = 
00023 WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_OVERLAPPEDWINDOW | WS_VISIBLE;
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: WinStatsGraph::Constructor
00027 //       Access: Public
00028 //  Description:
00029 ////////////////////////////////////////////////////////////////////
00030 WinStatsGraph::
00031 WinStatsGraph(WinStatsMonitor *monitor) :
00032   _monitor(monitor)
00033 {
00034   _window = 0;
00035   _graph_window = 0;
00036   _sizewe_cursor = LoadCursor(NULL, IDC_SIZEWE);
00037   _hand_cursor = LoadCursor(NULL, IDC_HAND);
00038   _bitmap = 0;
00039   _bitmap_dc = 0;
00040 
00041   _graph_left = 0;
00042   _graph_top = 0;
00043   _bitmap_xsize = 0;
00044   _bitmap_ysize = 0;
00045 
00046   _dark_color = RGB(51, 51, 51);
00047   _light_color = RGB(154, 154, 154);
00048   _user_guide_bar_color = RGB(130, 150, 255);
00049   _dark_pen = CreatePen(PS_SOLID, 1, _dark_color);
00050   _light_pen = CreatePen(PS_SOLID, 1, _light_color);
00051   _user_guide_bar_pen = CreatePen(PS_DASH, 1, _user_guide_bar_color);
00052 
00053   _drag_mode = DM_none;
00054   _potential_drag_mode = DM_none;
00055   _drag_scale_start = 0.0f;
00056 
00057   _pause = false;
00058 }
00059 
00060 ////////////////////////////////////////////////////////////////////
00061 //     Function: WinStatsGraph::Destructor
00062 //       Access: Public, Virtual
00063 //  Description:
00064 ////////////////////////////////////////////////////////////////////
00065 WinStatsGraph::
00066 ~WinStatsGraph() {
00067   _monitor = (WinStatsMonitor *)NULL;
00068   release_bitmap();
00069 
00070   DeleteObject(_dark_pen);
00071   DeleteObject(_light_pen);
00072   DeleteObject(_user_guide_bar_pen);
00073   
00074   Brushes::iterator bi;
00075   for (bi = _brushes.begin(); bi != _brushes.end(); ++bi) {
00076     HBRUSH brush = (*bi).second;
00077     DeleteObject(brush);
00078   }
00079 
00080   if (_graph_window) {
00081     DestroyWindow(_graph_window);
00082     _graph_window = 0;
00083   }
00084 
00085   if (_window) {
00086     DestroyWindow(_window);
00087     _window = 0;
00088   }
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: WinStatsGraph::new_collector
00093 //       Access: Public, Virtual
00094 //  Description: Called whenever a new Collector definition is
00095 //               received from the client.
00096 ////////////////////////////////////////////////////////////////////
00097 void WinStatsGraph::
00098 new_collector(int new_collector) {
00099 }
00100 
00101 ////////////////////////////////////////////////////////////////////
00102 //     Function: WinStatsGraph::new_data
00103 //       Access: Public, Virtual
00104 //  Description: Called whenever new data arrives.
00105 ////////////////////////////////////////////////////////////////////
00106 void WinStatsGraph::
00107 new_data(int thread_index, int frame_number) {
00108 }
00109 
00110 ////////////////////////////////////////////////////////////////////
00111 //     Function: WinStatsGraph::force_redraw
00112 //       Access: Public, Virtual
00113 //  Description: Called when it is necessary to redraw the entire graph.
00114 ////////////////////////////////////////////////////////////////////
00115 void WinStatsGraph::
00116 force_redraw() {
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: WinStatsGraph::changed_graph_size
00121 //       Access: Public, Virtual
00122 //  Description: Called when the user has resized the window, forcing
00123 //               a resize of the graph.
00124 ////////////////////////////////////////////////////////////////////
00125 void WinStatsGraph::
00126 changed_graph_size(int graph_xsize, int graph_ysize) {
00127 }
00128 
00129 ////////////////////////////////////////////////////////////////////
00130 //     Function: WinStatsGraph::set_time_units
00131 //       Access: Public, Virtual
00132 //  Description: Called when the user selects a new time units from
00133 //               the monitor pulldown menu, this should adjust the
00134 //               units for the graph to the indicated mask if it is a
00135 //               time-based graph.
00136 ////////////////////////////////////////////////////////////////////
00137 void WinStatsGraph::
00138 set_time_units(int unit_mask) {
00139 }
00140 
00141 ////////////////////////////////////////////////////////////////////
00142 //     Function: WinStatsGraph::set_scroll_speed
00143 //       Access: Public
00144 //  Description: Called when the user selects a new scroll speed from
00145 //               the monitor pulldown menu, this should adjust the
00146 //               speed for the graph to the indicated value.
00147 ////////////////////////////////////////////////////////////////////
00148 void WinStatsGraph::
00149 set_scroll_speed(double scroll_speed) {
00150 }
00151 
00152 ////////////////////////////////////////////////////////////////////
00153 //     Function: WinStatsGraph::set_pause
00154 //       Access: Public
00155 //  Description: Changes the pause flag for the graph.  When this flag
00156 //               is true, the graph does not update in response to new
00157 //               data.
00158 ////////////////////////////////////////////////////////////////////
00159 void WinStatsGraph::
00160 set_pause(bool pause) {
00161   _pause = pause;
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: WinStatsGraph::user_guide_bars_changed
00166 //       Access: Public
00167 //  Description: Called when the user guide bars have been changed.
00168 ////////////////////////////////////////////////////////////////////
00169 void WinStatsGraph::
00170 user_guide_bars_changed() {
00171   InvalidateRect(_window, NULL, TRUE);
00172   InvalidateRect(_graph_window, NULL, TRUE);
00173 }
00174 
00175 ////////////////////////////////////////////////////////////////////
00176 //     Function: WinStatsGraph::clicked_label
00177 //       Access: Public, Virtual
00178 //  Description: Called when the user single-clicks on a label.
00179 ////////////////////////////////////////////////////////////////////
00180 void WinStatsGraph::
00181 clicked_label(int collector_index) {
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: WinStatsGraph::close
00186 //       Access: Protected
00187 //  Description: Should be called when the user closes the associated
00188 //               window.  This tells the monitor to remove the graph.
00189 ////////////////////////////////////////////////////////////////////
00190 void WinStatsGraph::
00191 close() {
00192   WinStatsMonitor *monitor = _monitor;
00193   _monitor = (WinStatsMonitor *)NULL;
00194   if (monitor != (WinStatsMonitor *)NULL) {
00195     monitor->remove_graph(this);
00196   }
00197 }
00198 
00199 ////////////////////////////////////////////////////////////////////
00200 //     Function: WinStatsGraph::setup_label_stack
00201 //       Access: Protected
00202 //  Description: Sets up the label stack on the left edge of the
00203 //               frame.
00204 ////////////////////////////////////////////////////////////////////
00205 void WinStatsGraph::
00206 setup_label_stack() {
00207   _label_stack.setup(_window);
00208   move_label_stack();
00209 }
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: WinStatsGraph::move_label_stack
00213 //       Access: Protected
00214 //  Description: Repositions the label stack if its coordinates or
00215 //               size have changed.
00216 ////////////////////////////////////////////////////////////////////
00217 void WinStatsGraph::
00218 move_label_stack() {
00219   if (_label_stack.is_setup()) {
00220     RECT rect;
00221     GetClientRect(_window, &rect);
00222     
00223     rect.left += 8;
00224     rect.right = _left_margin - 8;
00225     rect.bottom -= _bottom_margin;
00226     
00227     _label_stack.set_pos(rect.left, rect.top, 
00228                          rect.right - rect.left, rect.bottom - rect.top);
00229   }
00230 }
00231 
00232 ////////////////////////////////////////////////////////////////////
00233 //     Function: WinStatsGraph::get_collector_brush
00234 //       Access: Protected
00235 //  Description: Returns a brush suitable for drawing in the indicated
00236 //               collector's color.
00237 ////////////////////////////////////////////////////////////////////
00238 HBRUSH WinStatsGraph::
00239 get_collector_brush(int collector_index) {
00240   Brushes::iterator bi;
00241   bi = _brushes.find(collector_index);
00242   if (bi != _brushes.end()) {
00243     return (*bi).second;
00244   }
00245 
00246   // Ask the monitor what color this guy should be.
00247   LRGBColor rgb = _monitor->get_collector_color(collector_index);
00248   int r = (int)(rgb[0] * 255.0f);
00249   int g = (int)(rgb[1] * 255.0f);
00250   int b = (int)(rgb[2] * 255.0f);
00251   HBRUSH brush = CreateSolidBrush(RGB(r, g, b));
00252 
00253   _brushes[collector_index] = brush;
00254   return brush;
00255 }
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: WinStatsGraph::window_proc
00259 //       Access: Protected
00260 //  Description: This window_proc should be called up to by the
00261 //               derived classes for any messages that are not
00262 //               specifically handled by the derived class.
00263 ////////////////////////////////////////////////////////////////////
00264 LONG WinStatsGraph::
00265 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00266   switch (msg) {
00267   case WM_DESTROY:
00268     close();
00269     break;
00270 
00271   case WM_SIZE:
00272     move_label_stack();
00273     InvalidateRect(hwnd, NULL, TRUE);
00274     break;
00275 
00276   case WM_SIZING:
00277     set_drag_mode(DM_sizing);
00278     break;
00279 
00280   case WM_EXITSIZEMOVE:
00281     set_drag_mode(DM_none);
00282     break;
00283 
00284   case WM_SETCURSOR:
00285     {
00286       // Why is it so hard to ask for the cursor position within the
00287       // window's client area?
00288       POINT point;
00289       GetCursorPos(&point);
00290       WINDOWINFO winfo;
00291       GetWindowInfo(hwnd, &winfo);
00292       const RECT &rect = winfo.rcClient;
00293       int x = point.x - rect.left;
00294       int y = point.y - rect.top;
00295       int width = rect.right - rect.left;
00296       int height = rect.bottom - rect.top;
00297 
00298       _potential_drag_mode = consider_drag_start(x, y, width, height);
00299 
00300       switch (_potential_drag_mode) {
00301       case DM_left_margin:
00302       case DM_right_margin:
00303         SetCursor(_sizewe_cursor);
00304         return TRUE;
00305 
00306       case DM_guide_bar:
00307         SetCursor(_hand_cursor);
00308         return TRUE;
00309 
00310       default:
00311       case DM_none:
00312         break;
00313       }
00314     }
00315     break;
00316 
00317   case WM_LBUTTONDOWN:
00318     if (_potential_drag_mode != DM_none) {
00319       set_drag_mode(_potential_drag_mode);
00320       _drag_start_x = (PN_int16)LOWORD(lparam);
00321       _drag_start_y = (PN_int16)HIWORD(lparam);
00322       SetCapture(_window);
00323     }
00324     return 0;
00325 
00326   case WM_MOUSEMOVE: 
00327     if (_drag_mode == DM_left_margin) {
00328       PN_int16 x = LOWORD(lparam);
00329       _left_margin += (x - _drag_start_x);
00330       _drag_start_x = x;
00331       InvalidateRect(hwnd, NULL, TRUE);
00332       move_label_stack();
00333       return 0;
00334 
00335     } else if (_drag_mode == DM_right_margin) {
00336       PN_int16 x = LOWORD(lparam);
00337       _right_margin += (_drag_start_x - x);
00338       _drag_start_x = x;
00339       InvalidateRect(hwnd, NULL, TRUE);
00340       return 0;
00341     }
00342     break;
00343 
00344   case WM_LBUTTONUP:
00345     set_drag_mode(DM_none);
00346     ReleaseCapture();
00347     break;
00348 
00349   case WM_PAINT:
00350     {
00351       PAINTSTRUCT ps;
00352       HDC hdc = BeginPaint(hwnd, &ps);
00353 
00354       // First, draw a frame around the graph.
00355       RECT rect;
00356       GetClientRect(hwnd, &rect);
00357 
00358       rect.left += _left_margin;
00359       rect.top += _top_margin;
00360       rect.right -= _right_margin;
00361       rect.bottom -= _bottom_margin;
00362 
00363       if (rect.right > rect.left && rect.bottom > rect.top) {
00364         DrawEdge(hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
00365 
00366         int graph_xsize = rect.right - rect.left;
00367         int graph_ysize = rect.bottom - rect.top;
00368         if (_bitmap_dc == 0 ||
00369             graph_xsize != _bitmap_xsize ||
00370             graph_ysize != _bitmap_ysize) {
00371           // Oops, we need to change the bitmap (and graph) size.
00372           changed_graph_size(graph_xsize, graph_ysize);
00373           move_graph_window(rect.left, rect.top, graph_xsize, graph_ysize);
00374           force_redraw();
00375         }
00376       }
00377 
00378       additional_window_paint(hdc);
00379 
00380       EndPaint(hwnd, &ps);
00381       return 0;
00382     }
00383 
00384   default:
00385     break;
00386   }
00387 
00388   return DefWindowProc(hwnd, msg, wparam, lparam);
00389 }
00390 
00391 ////////////////////////////////////////////////////////////////////
00392 //     Function: WinStatsGraph::graph_window_proc
00393 //       Access: Protected, Virtual
00394 //  Description: 
00395 ////////////////////////////////////////////////////////////////////
00396 LONG WinStatsGraph::
00397 graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00398   switch (msg) {
00399   case WM_DISPLAYCHANGE:
00400     setup_bitmap(_bitmap_xsize, _bitmap_ysize);
00401     force_redraw();
00402     break;
00403 
00404   case WM_LBUTTONDOWN:
00405     // Vector any uncaught WM_LBUTTONDOWN into the main window, so we
00406     // can drag margins, etc.
00407     if (_potential_drag_mode != DM_none) {
00408       PN_int16 x = LOWORD(lparam) + _graph_left;
00409       PN_int16 y = HIWORD(lparam) + _graph_top;
00410       return window_proc(_window, msg, wparam, MAKELPARAM(x, y));
00411     }
00412     break;
00413 
00414   case WM_LBUTTONUP:
00415     set_drag_mode(DM_none);
00416     ReleaseCapture();
00417     break;
00418 
00419   case WM_PAINT:
00420     {
00421       // Repaint the graph by copying the backing pixmap in.
00422       PAINTSTRUCT ps;
00423       HDC hdc = BeginPaint(hwnd, &ps);
00424 
00425       BitBlt(hdc, 0, 0, 
00426              _bitmap_xsize, _bitmap_ysize,
00427              _bitmap_dc, 0, 0,
00428              SRCCOPY);
00429 
00430       additional_graph_window_paint(hdc);
00431 
00432       EndPaint(hwnd, &ps);
00433       return 0;
00434     }
00435 
00436   default:
00437     break;
00438   }
00439 
00440   return DefWindowProc(hwnd, msg, wparam, lparam);
00441 }
00442 
00443 ////////////////////////////////////////////////////////////////////
00444 //     Function: WinStatsGraph::additional_window_paint
00445 //       Access: Protected, Virtual
00446 //  Description: This is called during the servicing of WM_PAINT; it
00447 //               gives a derived class opportunity to do some further
00448 //               painting into the window (the outer window, not the
00449 //               graph window).
00450 ////////////////////////////////////////////////////////////////////
00451 void WinStatsGraph::
00452 additional_window_paint(HDC hdc) {
00453 }
00454 
00455 ////////////////////////////////////////////////////////////////////
00456 //     Function: WinStatsGraph::additional_graph_window_paint
00457 //       Access: Protected, Virtual
00458 //  Description: This is called during the servicing of WM_PAINT; it
00459 //               gives a derived class opportunity to do some further
00460 //               painting into the graph window.
00461 ////////////////////////////////////////////////////////////////////
00462 void WinStatsGraph::
00463 additional_graph_window_paint(HDC hdc) {
00464 }
00465 
00466 ////////////////////////////////////////////////////////////////////
00467 //     Function: WinStatsGraph::consider_drag_start
00468 //       Access: Protected, Virtual
00469 //  Description: Based on the mouse position within the window's
00470 //               client area, look for draggable things the mouse
00471 //               might be hovering over and return the appropriate
00472 //               DragMode enum or DM_none if nothing is indicated.
00473 ////////////////////////////////////////////////////////////////////
00474 WinStatsGraph::DragMode WinStatsGraph::
00475 consider_drag_start(int mouse_x, int mouse_y, int width, int height) {
00476   if (mouse_x >= _left_margin - 2 && mouse_x <= _left_margin + 2) {
00477     return DM_left_margin;
00478   } else if (mouse_x >= width - _right_margin - 2 && mouse_x <= width - _right_margin + 2) {
00479     return DM_right_margin;
00480   }
00481 
00482   return DM_none;
00483 }
00484 
00485 ////////////////////////////////////////////////////////////////////
00486 //     Function: WinStatsGraph::set_drag_mode
00487 //       Access: Protected, Virtual
00488 //  Description: This should be called whenever the drag mode needs to
00489 //               change state.  It provides hooks for a derived class
00490 //               to do something special.
00491 ////////////////////////////////////////////////////////////////////
00492 void WinStatsGraph::
00493 set_drag_mode(WinStatsGraph::DragMode drag_mode) {
00494   _drag_mode = drag_mode;
00495 }
00496 
00497 ////////////////////////////////////////////////////////////////////
00498 //     Function: WinStatsGraph::move_graph_window
00499 //       Access: Protected, Virtual
00500 //  Description: Repositions the graph child window within the parent
00501 //               window according to the _margin variables.
00502 ////////////////////////////////////////////////////////////////////
00503 void WinStatsGraph::
00504 move_graph_window(int graph_left, int graph_top, int graph_xsize, int graph_ysize) {
00505   if (_graph_window == 0) {
00506     create_graph_window();
00507   }
00508 
00509   _graph_left = graph_left;
00510   _graph_top = graph_top;
00511 
00512   SetWindowPos(_graph_window, 0, 
00513                _graph_left, _graph_top,
00514                graph_xsize, graph_ysize,
00515                SWP_NOZORDER | SWP_SHOWWINDOW);
00516 
00517   if (graph_xsize != _bitmap_xsize || graph_ysize != _bitmap_ysize) {
00518     setup_bitmap(graph_xsize, graph_ysize);
00519   }
00520 }
00521 
00522 ////////////////////////////////////////////////////////////////////
00523 //     Function: WinStatsGraph::setup_bitmap
00524 //       Access: Private
00525 //  Description: Sets up a backing-store bitmap of the indicated size.
00526 ////////////////////////////////////////////////////////////////////
00527 void WinStatsGraph::
00528 setup_bitmap(int xsize, int ysize) {
00529   release_bitmap();
00530   _bitmap_xsize = max(xsize, 0);
00531   _bitmap_ysize = max(ysize, 0);
00532 
00533   HDC hdc = GetDC(_graph_window);
00534   _bitmap_dc = CreateCompatibleDC(hdc);
00535   _bitmap = CreateCompatibleBitmap(hdc, _bitmap_xsize, _bitmap_ysize);
00536   SelectObject(_bitmap_dc, _bitmap);
00537 
00538   RECT rect = { 0, 0, _bitmap_xsize, _bitmap_ysize };
00539   FillRect(_bitmap_dc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
00540 
00541   ReleaseDC(_window, hdc);
00542 }
00543 
00544 ////////////////////////////////////////////////////////////////////
00545 //     Function: WinStatsGraph::release_bitmap
00546 //       Access: Private
00547 //  Description: Frees the backing-store bitmap created by
00548 //               setup_bitmap().
00549 ////////////////////////////////////////////////////////////////////
00550 void WinStatsGraph::
00551 release_bitmap() {
00552   if (_bitmap) {
00553     DeleteObject(_bitmap);
00554     _bitmap = 0;
00555   }
00556   if (_bitmap_dc) {
00557     DeleteDC(_bitmap_dc);
00558     _bitmap_dc = 0;
00559   }
00560 }
00561 
00562 ////////////////////////////////////////////////////////////////////
00563 //     Function: WinStatsGraph::create_graph_window
00564 //       Access: Private
00565 //  Description: Creates the child window that actually holds the graph.
00566 ////////////////////////////////////////////////////////////////////
00567 void WinStatsGraph::
00568 create_graph_window() {
00569   if (_graph_window) {
00570     return;
00571   }
00572 
00573   HINSTANCE application = GetModuleHandle(NULL);
00574   register_graph_window_class(application);
00575 
00576   string window_title = "graph";
00577   DWORD window_style = WS_CHILD | WS_CLIPSIBLINGS;
00578 
00579   _graph_window = 
00580     CreateWindow(_graph_window_class_name, window_title.c_str(), window_style,
00581                  0, 0, 0, 0,
00582                  _window, NULL, application, 0);
00583   if (!_graph_window) {
00584     nout << "Could not create graph window!\n";
00585     exit(1);
00586   }
00587 
00588   SetWindowLongPtr(_graph_window, 0, (LONG_PTR)this);
00589 }
00590 
00591 ////////////////////////////////////////////////////////////////////
00592 //     Function: WinStatsGraph::register_graph_window_class
00593 //       Access: Private, Static
00594 //  Description: Registers the window class for the stripChart window, if
00595 //               it has not already been registered.
00596 ////////////////////////////////////////////////////////////////////
00597 void WinStatsGraph::
00598 register_graph_window_class(HINSTANCE application) {
00599   if (_graph_window_class_registered) {
00600     return;
00601   }
00602 
00603   WNDCLASS wc;
00604 
00605   ZeroMemory(&wc, sizeof(WNDCLASS));
00606   wc.style = CS_DBLCLKS;
00607   wc.lpfnWndProc = (WNDPROC)static_graph_window_proc;
00608   wc.hInstance = application;
00609   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
00610   wc.hbrBackground = NULL;
00611   wc.lpszMenuName = NULL;
00612   wc.lpszClassName = _graph_window_class_name;
00613 
00614   // Reserve space to associate the this pointer with the window.
00615   wc.cbWndExtra = sizeof(WinStatsGraph *);
00616   
00617   if (!RegisterClass(&wc)) {
00618     nout << "Could not register graph window class!\n";
00619     exit(1);
00620   }
00621 
00622   _graph_window_class_registered = true;
00623 }
00624 
00625 ////////////////////////////////////////////////////////////////////
00626 //     Function: WinStatsGraph::static_graph_window_proc
00627 //       Access: Private, Static
00628 //  Description: 
00629 ////////////////////////////////////////////////////////////////////
00630 LONG WINAPI WinStatsGraph::
00631 static_graph_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00632   WinStatsGraph *self = (WinStatsGraph *)GetWindowLongPtr(hwnd, 0);
00633   if (self != (WinStatsGraph *)NULL && self->_graph_window == hwnd) {
00634     return self->graph_window_proc(hwnd, msg, wparam, lparam);
00635   } else {
00636     return DefWindowProc(hwnd, msg, wparam, lparam);
00637   }
00638 }
 All Classes Functions Variables Enumerations