24 define LEFT_MARGIN = 10;
25 define RIGHT_MARGIN = 10;
26 define TOP_MARGIN = 10;
27 define BOTTOM_MARGIN = 10;
29 enum VerticalAlignment { middle, top, bottom };
31 enum HorizontalAlignment { none, left, middle, right };
33 define CELL_SPACING = 0;
35 class RenderFlags { bool lineW:1,width:1,render:1,minW:1; };
37 enum InputType { text, submit, checkbox, radio, hidden };
39 class ImageEntry : struct
41 ImageEntry prev, next;
54 bitmapPtrs.Free(null);
58 class FontEntry : struct
72 class RequestLink : OldLink
77 class AlignedObject : struct
79 AlignedObject prev, next;
85 static HTMLView browserWindow;
87 class ObjectThread : Thread
89 bool objectThreadDead;
90 bool objectThreadTerminate;
91 Semaphore objectThreadSemaphore {};
95 objectThreadDead = false;
96 for(;!objectThreadTerminate;)
98 if(objectRequests.first)
102 //((GuiApplication)__thisModule).Lock();
104 for(;!objectThreadTerminate;)
109 char path[MAX_LOCATION], referer[MAX_LOCATION];
112 for(request = objectRequests.first; request && request.processed; request = (RequestLink)request.next);
115 request.processed = true;
116 objectsMutex.Release();
119 entry = request.data;
121 strcpy(path, entry.src);
122 //strcpy(referer, browserWindow.location ? browserWindow.location : "");
123 strcpy(referer, entry.referer); //browserWindow.location ? browserWindow.location : "");
125 //((GuiApplication)__thisModule).Unlock();
127 if(strstr(path, "http://") == path)
129 HTTPFile httpFile {};
132 //printf("Opening URL\n");
134 //((GuiApplication)__thisModule).PauseNetworkEvents();
135 if(httpFile.OpenURL(path, referer, null))
137 char extension[MAX_EXTENSION];
138 entry.bitmap = Bitmap { alphaBlend = true };
139 //printf("Loading File\n");
140 entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
144 entry.missing = true;
145 //((GuiApplication)__thisModule).ResumeNetworkEvents();
149 file = FileOpen(path, read);
151 entry.missing = true;
154 char extension[MAX_EXTENSION];
155 entry.bitmap = Bitmap { alphaBlend = true };
156 entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
163 objectRequests.Remove(request);
165 objectsMutex.Release();
167 ((GuiApplication)__thisModule).Lock();
168 if(!objectThreadTerminate)
171 Window rootWindow = browserWindow.rootWindow;
173 display = rootWindow.parent.display;
175 display = rootWindow.display;
180 entry.bitmap.MakeDD(browserWindow.displaySystem);
181 if(entry.bitmap && entry.bitmap.alphaBlend)
183 entry.bitmap.Convert(null, pixelFormat888, null);
184 // entry.bitmap.displaySystem = displaySystem;
187 for(bitmapPtr = entry.bitmapPtrs.first; bitmapPtr; bitmapPtr = bitmapPtr.next)
189 *((Bitmap*) bitmapPtr.data) = entry.bitmap;
191 browserWindow.ComputeMinSizes();
192 browserWindow.ComputeSizes();
193 browserWindow.PositionForms();
194 browserWindow.Update(null);
196 // ((GuiApplication)__thisModule).UpdateDisplay();
200 // TRIED MOVING THIS HERE BECAUSE OF printf("bug") in GuiApplication if(window.display.current)
201 ((GuiApplication)__thisModule).UpdateDisplay();
203 ((GuiApplication)__thisModule).Unlock();
205 //((GuiApplication)__thisModule).Unlock();
209 //printf("Waiting for Object Thread Semaphore\n");
210 objectThreadSemaphore.Wait();
213 objectThreadDead = true;
218 static ObjectThread objectThread1 { };
219 static ObjectThread objectThread2 { };
220 static ObjectThread objectThread3 { };
221 static ObjectThread objectThread4 { };
222 static Mutex objectsMutex {};
223 static OldList imageCache;
224 /*static */OldList fontCache;
226 static OldList objectRequests;
228 /*static void WriteBlock(File f, Block block)
230 static int indent = 0;
234 for(c = 0; c<indent; c++)
240 f.Printf("Text: %s\n", block.text);
243 f.Printf("Image: %d %d %s\n", block.w, block.h, block.src);
252 f.Printf("Anchor: %s\n", block.src);
255 f.Printf("Font: %s, %d\n", block.face, block.size);
258 f.Printf("Center\n");
271 for(child = block.subBlocks.first; child; child = child.next)
274 WriteBlock(f, child);
279 static void ComputeImageSize(Block block)
283 if(block.type == IMAGE)
286 block.w = block.width;
288 block.w = block.bitmap ? block.bitmap.width : 0;
291 block.h = block.height;
293 block.h = block.bitmap ? block.bitmap.height : 0;
295 for(child = block.subBlocks.first; child; child = child.next)
296 ComputeImageSize(child);
304 bool OnLoadGraphics()
308 for(entry = imageCache.first; entry; entry = entry.next)
310 entry.bitmap.MakeDD(displaySystem);
311 if(entry.bitmap && entry.bitmap.alphaBlend)
313 entry.bitmap.Convert(null, pixelFormat888, null);
314 // entry.bitmap.displaySystem = displaySystem;
317 for(fEntry = fontCache.first; fEntry; fEntry = fEntry.next)
320 fEntry.font = displaySystem.LoadFont(fEntry.face, fEntry.size, fEntry.attribs);
325 void OnUnloadGraphics()
329 while((entry = imageCache.first))
331 imageCache.Remove(entry);
334 while((fontEntry = fontCache.first))
336 displaySystem.UnloadFont(fontEntry.font);
337 fontCache.Remove(fontEntry);
343 class HTMLView : Window
346 BitmapResource missing { "<:ecere>emblems/unreadable.png", window = sharedWindow /*this*/ };
348 Block overLink, clickedLink;
352 void ComputeMinSizes()
356 ComputeImageSize(html.body);
358 // Pre compute some stuff
360 Block block = html.body;
364 Surface surface = display.GetSurface(0,0,null);
367 surface.TextFont(html.defaultFont.font.font);
374 ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, MAXINT, 0, RenderFlags { minW = true }, 0, null, null, null, true, 0, LEFT_MARGIN);
376 textPos = nextTextPos;
384 void Clear(Block block)
388 if(block.type != TABLE && block.type != IMAGE)
393 if(block.type == TABLE)
395 block.columns.Free(null);
397 if(block.type != IMAGE)
403 block.rowSpan = block.span = 1;
406 for(b = block.subBlocks.first; b; b = b.next)
413 int width = clientSize.w;
414 int height = clientSize.h;
415 Block block = html.body;
416 int totalWidth = 0, totalHeight = 0;
420 Surface surface = display.GetSurface(0,0,null);
423 width = parent.clientSize.w;
425 height = parent.clientSize.h;
429 int maxH = height - BOTTOM_MARGIN;
431 if(html.defaultFont.font)
432 surface.TextFont(html.defaultFont.font.font);
438 int maxW = width - (LEFT_MARGIN + RIGHT_MARGIN);
441 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags { lineW = true, width = true }, 0, null, null, &changeLine, true, y, LEFT_MARGIN);
445 textPos = nextTextPos;
447 totalWidth = Max(totalWidth, w);
451 totalHeight = y + BOTTOM_MARGIN;
452 totalWidth += LEFT_MARGIN + RIGHT_MARGIN;
454 SetScrollArea(totalWidth, totalHeight, false);
455 SetScrollArea(totalWidth, totalHeight, false);
458 if(!initSize.w || !initSize.h)
459 clientSize = Size {!initSize.w ? totalWidth : clientSize.w, !initSize.h ? totalHeight : clientSize.h };
462 void CreateForms(Block block)
466 if(block.type == INPUT)
468 switch(block.inputType)
471 block.window = Button { this, text = block.value, position = Point { 10, 50 }, id = (int64)block, NotifyClicked = ButtonClicked, isDefault = true };
473 block.window.size = { w = (int)(block.size * 8) };
476 ((Button)block.window).bitmap = { block.src };
477 ((Button)block.window).bevel = false;
479 eInstance_IncRef(block.window);
480 block.window.Create();
481 block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
482 //if(!html.defaultButton) html.defaultButton = block.window;
485 block.window = Button { this, isCheckbox = true, position = Point { 10, 100 }, id = (int64)block, NotifyClicked = ButtonClicked };
486 eInstance_IncRef(block.window);
487 block.window.Create();
488 block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
491 block.window = Button { this, isRadio = true, position = Point { 10, 100 }, id = (int64)block, NotifyClicked = ButtonClicked };
492 eInstance_IncRef(block.window);
493 block.window.Create();
494 block.window.cursor = ((GuiApplication)__thisModule).GetCursor(arrow);
497 block.window = EditBox { this, contents = block.value, size = { w = (int)(block.size * 8) }, position = Point { 10, 20 }, id = (int64)block };
500 ((EditBox)block.window).size.w = block.parent.width;
502 eInstance_IncRef(block.window);
503 block.window.Create();
506 /*if(!activeChild && block.window)
507 block.window.Activate();*/
510 for(child = block.subBlocks.last; child; child = child.prev)
514 void LoadGraphics(Block block, void **previous)
518 if(block.src && (block.type == IMAGE || block.type == TD || block.type == TABLE))
520 char path[MAX_LOCATION];
521 ImageEntry entry = null;
523 strcpy(path, location ? location : "");
524 if(location && path[strlen(path)-1] != '/')
526 if(block.src[0] == '/' && block.src[1] == '/')
528 strcpy(path, "http:");
529 strcat(path, block.src);
532 PathCat(path, block.src);
534 if(!strstr(path, "File://"))
536 for(entry = imageCache.first; entry; entry = entry.next)
537 if(!strcmp(entry.src, path))
543 entry = ImageEntry { src = CopyString(path), referer = CopyString(location) };
544 imageCache.Add(entry);
547 block.imageEntry = entry;
548 block.entryPtr = OldLink { data = &block.bitmap };
549 entry.bitmapPtrs.Add(block.entryPtr);
552 block.bitmap = entry.bitmap;
555 if(strstr(path, "http://") == path || strstr(path, "https://") == path)
559 for(request = objectRequests.first; request; request = (RequestLink)request.next)
561 if(request.data == entry)
566 request = RequestLink { data = entry };
567 objectRequests.Insert(*previous, request);
569 objectThread1.objectThreadSemaphore.Release();
570 objectThread2.objectThreadSemaphore.Release();
571 objectThread3.objectThreadSemaphore.Release();
572 objectThread4.objectThreadSemaphore.Release();
574 else if(*previous != request)
576 objectRequests.Move(request, *previous);
579 objectsMutex.Release();
583 // ADDED THIS TO LOAD LOCAL FILES RIGHT HERE...
585 File file = FileOpen(path, read);
587 entry.missing = true;
590 char extension[MAX_EXTENSION];
591 entry.bitmap = Bitmap { alphaBlend = true };
592 entry.bitmap.LoadFromFile(file, GetExtension(path, extension), null);
594 entry.bitmap.MakeDD(displaySystem);
598 for(bitmapPtr = entry.bitmapPtrs.first; bitmapPtr; bitmapPtr = bitmapPtr.next)
600 *((Bitmap*) bitmapPtr.data) = entry.bitmap;
602 block.bitmap = entry.bitmap;
605 block.font = block.parent.font;
606 block.textColor = block.parent.textColor;
608 else if(block.type == FONT || block.type == ANCHOR)
611 for(entry = fontCache.first; entry; entry = entry.next)
613 if(!strcmpi(entry.face, block.face) &&
614 entry.size == block.size &&
615 entry.attribs == block.attribs)
623 entry = FontEntry { font = displaySystem.LoadFont(block.face, block.size, block.attribs), size = block.size, attribs = block.attribs, face = CopyString(block.face) };
624 fontCache.Add(entry);
631 else if(block.parent)
633 block.font = block.parent.font;
634 block.textColor = block.parent.textColor;
638 block.textColor = black;
641 for(child = block.subBlocks.first; child; child = child.next)
642 LoadGraphics(child, previous);
645 void NormalizeSelection(Block * startBlock, int * startSel, Block * endBlock, int * endSel)
647 bool selAfter = false;
649 for(b = selBlock; b; b = GetNextBlock(b))
651 if(b != selBlock && b == textBlock)
658 if(textBlock == selBlock)
660 *startSel = Min(selPosition, curPosition);
661 *endSel = Max(selPosition, curPosition);
662 *startBlock = *endBlock = textBlock;
666 *startBlock = textBlock;
667 *startSel = curPosition;
668 *endSel = selPosition;
669 *endBlock = selBlock;
673 *startBlock = selBlock;
674 *startSel = selPosition;
675 *endSel = curPosition;
676 *endBlock = textBlock;
682 Block block = html.body;
686 int maxH = clientSize.h - BOTTOM_MARGIN;
687 OldList leftObjects { };
688 OldList rightObjects { };
689 AlignedObject object, nextObject;
691 Surface surface = display.GetSurface(0,0,null);
695 if(html.defaultFont.font)
696 surface.TextFont(html.defaultFont.font.font);
706 int thisLineCentered = centered;
710 right = clientSize.w - RIGHT_MARGIN;
712 for(object = leftObjects.last; object; object = nextObject)
714 nextObject = object.prev;
715 if(y < object.untilY || object.next)
718 leftObjects.Delete(object);
720 for(object = rightObjects.last; object; object = nextObject)
722 nextObject = object.prev;
723 if(y < object.untilY || object.next)
726 rightObjects.Delete(object);
728 right = Max(left, right);
731 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, true, 0 /*y*/, LEFT_MARGIN);
734 x = Max(left,(left + right - w) / 2);
740 PositionLine(this, surface, x - scroll.x, y - scroll.y,
741 maxW, newH, block, textPos, nextBlock, nextTextPos,
742 left - scroll.x, right - scroll.x);
747 textPos = nextTextPos;
753 void Open(char * location, char * firstReferer)
755 HTTPFile f { /*reuseConnection = false*/ };
756 char referer[MAX_LOCATION] = "";
757 char relocation[MAX_LOCATION];
760 strcpy(relocation, location);
762 // PrintLn("\n\n\nOpening new location: ", location, "\n");
764 if(strstr(location, "http://") != location && strstr(location, "https://") != location)
766 if(!FileExists(location))
768 strcpy(relocation, "http://");
769 strcat(relocation, location);
774 f = (HTTPFile)FileOpen(location, read);
784 strcpy(referer, firstReferer);
789 SetScrollArea(0,0,0);
794 char path[MAX_LOCATION];
797 delete this.location;
798 this.location = CopyString(relocation);
799 fileName = this.location;
800 ((GuiApplication)__thisModule).UpdateDisplay();
802 if(!(opened = f.OpenURL(this.location, referer, relocation)) && !strcmp(this.location, relocation))
807 //printf("Relocated to %s\n", relocation);
809 strcpy(referer, this.location);
811 // Fix up relocation relative paths
812 strcpy(path, this.location);
813 if(path[strlen(path)-1] != '/')
815 if(relocation[0] == '/' && relocation[1] == '/')
817 strcpy(path, "http:");
818 strcat(path, relocation);
821 PathCat(path, relocation);
822 strcpy(relocation, path);
825 delete this.location;
826 this.location = CopyString(relocation);
827 fileName = this.location;
831 bool isHTTP = eClass_IsDerived(f._class, class(HTTPFile));
832 void * previous = null;
833 bool isImage = false;
834 bool isPlain = isHTTP ? false : true;
836 // Handle known types
837 if(isHTTP && f.contentType)
839 if(strstr(f.contentType, "image/") == f.contentType)
841 else if(strstr(f.contentType, "text/") == f.contentType && strnicmp(f.contentType + 5, "html", 4))
846 const String imageExt[] = { "jpg", "jpeg", "bmp", "pcx", "png", "gif" };
847 const String htmlExt[] = { "html", "htm", "php" };
848 const String textExt[] = { "c", "h", "ec", "eh", "epj", "cpp", "cxx", "cc", "hpp", "hxx", "hh", "m", "java", "cs", "py", "Makefile", "mk", "cf" };
849 char ext[MAX_EXTENSION];
851 GetExtension(fileName, ext);
852 for(i = 0; i < sizeof(imageExt) / sizeof(imageExt[0]); i++)
853 if(!strcmpi(ext, imageExt[i]))
859 for(i = 0; i < sizeof(htmlExt) / sizeof(htmlExt[0]); i++)
860 if(!strcmpi(ext, htmlExt[i]))
866 for(i = 0; i < sizeof(textExt) / sizeof(textExt[0]); i++)
867 if(!strcmpi(ext, textExt[i]))
877 html.body = HTMLFile::AddBlock(html.block, BODY);
879 subBlock = HTMLFile::AddBlock(html.body, IMAGE);
880 subBlock.valign = bottom;
881 subBlock.halign = middle;
882 subBlock.src = CopyString(fileName);
883 html.defaultFont.type = FONT;
884 html.defaultFont.face = CopyString("Times New Roman");
893 String cd = eClass_IsDerived(f._class, class(HTTPFile)) ? f.contentDisposition : null;
895 String tmpPath = PrintString("File://", (uintptr)tmp);
897 size = tmp.GetSize();
900 html.defaultFont.type = FONT;
901 html.defaultFont.face = CopyString("Courier New");
905 char fn[MAX_LOCATION];
906 while(GetKeyWordEx(&cd, fn, sizeof(fn), true, false))
908 if(!strcmp(fn, "filename") && GetKeyWordEx(&cd, fn, sizeof(fn), true, true))
910 html.titleBlock = HTMLFile::AddBlock(html.block, TITLE);
911 subBlock = HTMLFile::AddBlock(html.titleBlock, TEXT);
912 subBlock.text = CopyString(fn);
913 subBlock.textLen = strlen(fn);
918 html.body = HTMLFile::AddBlock(html.block, BODY);
919 html.block = html.body;
921 text = new char[size + 1];
922 len = tmp.Read(text, 1, size);
929 Block textBlock = HTMLFile::AddBlock(html.block, TEXT);
934 if(ch == '\n' || ch == '\r' || !ch)
937 textBlock.text = renew textBlock.text char[textBlock.textLen + 1 + len];
938 memmove(textBlock.text + len, textBlock.text, textBlock.textLen + 1);
939 memcpy(textBlock.text, text + start, len);
940 textBlock.textLen += len;
943 Block block { type = BR, parent = textBlock.parent };
944 Block newBlock { type = TEXT, parent = textBlock.parent };
946 textBlock.parent.subBlocks.Insert(textBlock, block);
947 textBlock.parent.subBlocks.Insert(block, newBlock);
949 newBlock.textLen = 0;
950 newBlock.text = new char[1];
951 newBlock.text[0] = 0;
953 textBlock = newBlock;
955 if(ch == '\r' && text[c+1] == '\n') c++;
960 html.block = html.block.parent;
972 delete this.location;
973 this.location = CopyString(html.baseHRef);
976 LoadGraphics(html.defaultFont, &previous);
977 html.block.font = html.defaultFont.font;
978 LoadGraphics(html.block, &previous);
979 CreateForms(html.block);
988 File f = FileOpen("debug2.txt", write);
991 WriteBlock(f, html.body);
998 ((GuiApplication)__thisModule.application).Unlock();
999 // PrintLn("At position ", f.Tell(), " for ", fileName);
1001 ((GuiApplication)__thisModule.application).Lock();
1002 NotifyPageOpened(master);
1005 void OpenFile(File f, char * firstReferer)
1007 char referer[MAX_LOCATION] = "";
1008 bool opened = false;
1015 strcpy(referer, firstReferer);
1020 SetScrollArea(0,0,0);
1024 this.location = null;
1025 fileName = this.location;
1029 void * previous = null;
1031 LoadGraphics(html.defaultFont, &previous);
1032 html.block.font = html.defaultFont.font;
1033 LoadGraphics(html.block, &previous);
1034 CreateForms(html.block);
1041 File f = FileOpen("debug2.txt", write);
1044 WriteBlock(f, html.body);
1050 NotifyPageOpened(master);
1053 bool ScrollToAnchor(Block block, const char * anchor)
1055 bool result = false;
1056 if(block.type == ANCHOR && block.anchor && !strcmpi(block.anchor, anchor))
1058 SetScrollPosition(0, block.startY);
1064 for(subBlock = block.subBlocks.first; subBlock; subBlock = subBlock.next)
1066 if((result = ScrollToAnchor(subBlock, anchor)))
1073 bool GoToAnchor(const char * anchor)
1075 return anchor ? ScrollToAnchor(html.block, anchor) : false;
1078 virtual bool Window::NotifyPageOpened();
1082 objectThread1.objectThreadTerminate = true;
1083 objectThread2.objectThreadTerminate = true;
1084 objectThread3.objectThreadTerminate = true;
1085 objectThread4.objectThreadTerminate = true;
1086 ((GuiApplication)__thisModule).Unlock();
1087 objectThread1.objectThreadSemaphore.Release();
1088 objectThread2.objectThreadSemaphore.Release();
1089 objectThread3.objectThreadSemaphore.Release();
1090 objectThread4.objectThreadSemaphore.Release();
1093 while(!objectThread1.objectThreadDead ||
1094 !objectThread2.objectThreadDead ||
1095 !objectThread3.objectThreadDead ||
1096 !objectThread4.objectThreadDead)
1098 // ((GuiApplication)__thisModule).ProcessNetworkEvents();
1102 //objectThread.Wait();
1103 objectRequests.Free(null);
1105 ((GuiApplication)__thisModule).Lock();
1110 browserWindow = this;
1111 objectThread1.objectThreadTerminate = false;
1112 objectThread2.objectThreadTerminate = false;
1113 objectThread3.objectThreadTerminate = false;
1114 objectThread4.objectThreadTerminate = false;
1116 objectThread1.Create();
1117 objectThread2.Create();
1118 objectThread3.Create();
1119 objectThread4.Create();
1124 location = CopyString(location);
1133 Open(location, null);
1137 void OnResize(int width, int height)
1147 // For text selection
1148 Block textBlock, selBlock;
1149 int curPosition, selPosition;
1150 bool isSelected; // Persistent state changed by RenderLine
1152 void OnRedraw(Surface surface)
1154 Block block = html.body;
1158 int maxH = clientSize.h - BOTTOM_MARGIN;
1159 OldList leftObjects { };
1160 OldList rightObjects { };
1163 AlignedObject object, nextObject;
1165 surface.SetBackground(html.background);
1166 if(html.background.a < 255)
1167 surface.Area(0,0,clientSize.w,clientSize.h);
1169 surface.Clear(colorBuffer);
1170 if(html.defaultFont.font) // TOFIX: Null! (No font set?)
1171 surface.TextFont(html.defaultFont.font.font);
1172 surface.SetForeground(html.defaultFont.textColor);
1182 int thisLineCentered = centered;
1186 right = clientSize.w - RIGHT_MARGIN;
1188 for(object = leftObjects.last; object; object = nextObject)
1190 nextObject = object.prev;
1191 if(y < object.untilY || object.next)
1194 leftObjects.Delete(object);
1196 for(object = rightObjects.last; object; object = nextObject)
1198 nextObject = object.prev;
1199 if(y < object.untilY || object.next)
1202 rightObjects.Delete(object);
1204 right = Max(left, right);
1205 maxW = right - left;
1207 font = surface.font;
1208 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
1209 surface.font = font;
1210 if(thisLineCentered)
1211 x = Max(left,(left + right - w) / 2);
1215 surface.TextFont(font);
1217 RenderLine(this, surface, x - scroll.x, y - scroll.y, maxW, newH, block, textPos, nextBlock, nextTextPos, left - scroll.x, right - scroll.x);
1222 textPos = nextTextPos;
1226 void OnVScroll(ScrollBarAction action, int position, Key key)
1231 bool OnKeyHit(Key key, unichar character)
1236 CycleChildren(true, false, false, true);
1239 CycleChildren(false, false, false, true);
1241 case left: case right:
1242 horzScroll.OnKeyHit(key, character);
1244 case down: case up: case pageDown: case pageUp:
1245 vertScroll.OnKeyHit(key, character);
1251 bool OnKeyDown(Key key, unichar character)
1257 vertScroll.OnKeyDown(home, character);
1258 horzScroll.OnKeyDown(home, character);
1263 vertScroll.OnKeyDown(end, character);
1264 horzScroll.OnKeyDown(end, character);
1271 void OnHScroll(ScrollBarAction action, int position, Key key)
1276 bool PickHTML(int pickX, int pickY, Block* pickBlock, int * pickTextPos)
1278 bool result = false;
1279 Block block = html.body;
1283 int maxH = clientSize.h - BOTTOM_MARGIN;
1284 OldList leftObjects { };
1285 OldList rightObjects { };
1286 AlignedObject object, nextObject;
1288 Surface surface = display.GetSurface(0,0,null);
1291 if(html.defaultFont.font) // TOFIX: Null! (No font set?)
1292 surface.TextFont(html.defaultFont.font.font);
1300 int thisLineCentered = centered;
1301 Font font = surface.font;
1305 right = clientSize.w - RIGHT_MARGIN;
1307 for(object = leftObjects.last; object; object = nextObject)
1309 nextObject = object.prev;
1310 if(y < object.untilY || object.next)
1313 leftObjects.Delete(object);
1315 for(object = rightObjects.last; object; object = nextObject)
1317 nextObject = object.prev;
1318 if(y < object.untilY || object.next)
1321 rightObjects.Delete(object);
1323 right = Max(left, right);
1324 maxW = right - left;
1326 newH = ComputeLine(surface, block, textPos, &nextBlock, &nextTextPos, ¢ered, &w, maxW, maxH - y, RenderFlags {}, y, &leftObjects, &rightObjects, &changeLine, false, 0, 0);
1327 if(thisLineCentered)
1328 x = Max(left,(left + right - w) / 2);
1332 surface.font = font;
1334 if(PickLine(this, surface, x - scroll.x, y - scroll.y,
1335 maxW, newH, block, textPos, nextBlock, nextTextPos,
1336 left - scroll.x, right - scroll.x, pickX, pickY, pickBlock, pickTextPos))
1346 textPos = nextTextPos;
1351 for(object = leftObjects.last; object; object = nextObject)
1353 nextObject = object.prev;
1354 leftObjects.Delete(object);
1356 for(object = rightObjects.last; object; object = nextObject)
1358 nextObject = object.prev;
1359 rightObjects.Delete(object);
1364 bool OnMouseMove(int x, int y, Modifiers mods)
1366 Block pickBlock = null;
1367 Block linkBlock = null;
1368 int pickTextPos = 0;
1370 if(!mods.isSideEffect)
1372 PickHTML(x,y, &pickBlock, &pickTextPos);
1376 for(linkBlock = pickBlock; linkBlock; linkBlock = linkBlock.parent)
1378 if(linkBlock.type == ANCHOR)
1384 if(linkBlock.href && strstr(linkBlock.href, "edit://") == linkBlock.href)
1385 cursor = ((GuiApplication)__thisModule).GetCursor(iBeam);
1387 cursor = ((GuiApplication)__thisModule).GetCursor(hand);
1388 overLink = linkBlock;
1392 if(pickBlock && pickBlock.type == TEXT)
1394 cursor = ((GuiApplication)__thisModule).GetCursor(iBeam);
1398 cursor = ((GuiApplication)__thisModule).GetCursor(arrow); //null);
1402 overBlock = pickBlock;
1403 overPos = pickTextPos;
1408 bool OnLeftButtonDown(int x, int y, Modifiers mods)
1410 OnMouseMove(x, y, mods);
1413 clickedLink = overLink;
1420 virtual bool OnOpen(char * href)
1422 char newLocation[MAX_LOCATION];
1424 strcpy(newLocation, location ? location : "");
1425 if(newLocation[strlen(newLocation)-1] != '/')
1426 PathCat(newLocation, "..");
1427 if(href[0] == '/' && href[1] == '/')
1429 strcpy(newLocation, "http:");
1430 strcat(newLocation, href);
1433 PathCat(newLocation, href);
1435 Open(newLocation, null);
1439 bool OnLeftButtonUp(int x, int y, Modifiers mods)
1444 if(clickedLink == overLink && clickedLink.href)
1446 if(OnOpen(clickedLink.href))
1453 void AddFormControls(char * location, Block block)
1456 if(block.type == INPUT)
1458 switch(block.inputType)
1468 if(location[strlen(location)-1] != '?')
1470 strcat(location, "&");
1472 strcat(location, block.name);
1473 strcat(location, "=");
1475 len = strlen(location);
1477 text = ((EditBox)block.window).contents;
1479 for(c = 0; text[c]; c++)
1482 location[len++] = '+';
1485 location[len++] = text[c];
1488 location[len] = '\0';
1494 for(child = block.subBlocks.first; child; child = child.next)
1496 AddFormControls(location, child);
1500 bool ButtonClicked(Button button, int x, int y, Modifiers mods)
1502 Block block = (Block)button.id;
1503 if(block.inputType == submit)
1507 for(formBlock = block; formBlock; formBlock = formBlock.parent)
1508 if(formBlock.type == FORM)
1511 if(formBlock && formBlock.action)
1513 char newLocation[MAX_LOCATION];
1515 strcpy(newLocation, location);
1516 if(newLocation[strlen(newLocation)-1] != '/')
1517 PathCat(newLocation, "..");
1519 if(formBlock.action[0] == '/' && formBlock.action[1] == '/')
1521 strcpy(newLocation, "http:");
1522 strcat(newLocation, formBlock.action);
1525 PathCat(newLocation, formBlock.action);
1526 strcat(newLocation, "?");
1530 strcat(newLocation, block.name);
1531 strcat(newLocation, "=");
1534 AddFormControls(newLocation, formBlock);
1536 Open(newLocation, null);
1546 html.background = white;
1551 delete this.location;
1553 html.block.ClearEntries();
1556 property const char * location
1562 location = CopyString(value);
1564 Open(location, null);
1566 get { return location; }
1569 property String title
1573 String title = html.title;
1574 return title ? title : location;